<script setup lang="ts">
import { ref, onMounted, computed, onUnmounted, watch, nextTick } from 'vue'
import { lzcAPIGateway } from "@lazycatcloud/sdk"
import pinyin from 'pinyin'
import { loadAppHistory, addToHistory, getLastOpenedApp, clearAppHistory } from '../utils/appHistory'
import { loadSettings, saveSidebarPositions, saveWindowMode, clearSettings, saveQuickSwitchShortcut, type SidebarPosition as SettingsSidebarPosition, type WindowMode as SettingsWindowMode, type KeyboardShortcut } from '../utils/settings'

interface AppInfo {
  appid: string
  title?: string
  description?: string
  icon?: string
  domain: string
  status?: number
  instanceStatus?: number
  [key: string]: any
}

type SidebarPosition = 'left' | 'right' | 'top' | 'bottom'
type WindowMode = 'single' | 'multi' // 单应用模式 / 多应用模式
type TileIndex = 0 | 1 | 2 | 3

interface WindowData {
  id: string
  title: string
  url: string
  domain: string
  tileIndex: TileIndex
  isDragging: boolean
  // 布局属性（由计算得出）
  x: number
  y: number
  width: number
  height: number
}

interface Layout {
  cols: number
  rows: number
  tiles: Array<{
    index: TileIndex
    x: number
    y: number
    width: number
    height: number
  }>
}

const apps = ref<AppInfo[]>([])
const currentDomain = ref<string>(window.location.host)
const searchQuery = ref<string>('')
const sidebarCollapsed = ref<boolean>(false)
const currentAppDomain = ref<string>('')
const appHistory = ref<AppInfo[]>([]) // 历史打开的应用，后进先出（从localStorage加载）
const openedApps = ref<string[]>([]) // 已打开的应用domain列表（用于渲染iframe）
const sidebarRef = ref<HTMLElement | null>(null)
const expandBtnRef = ref<HTMLElement | null>(null)
const searchInputRef = ref<HTMLInputElement | null>(null)

// 侧边栏位置设置（多选）
const sidebarPositions = ref<SidebarPosition[]>(['left'])

// 当前侧边栏显示位置（用于UI显示，从启用的位置中选择）
const sidebarPosition = ref<SidebarPosition>('left')

// 窗口模式设置
const windowMode = ref<WindowMode>('single')

// 预先触发设置加载请求（页面加载即发起）
const loadSettingsPromise = loadSettings()

// 设置面板显示状态
const settingsVisible = ref<boolean>(false)

// 快捷切换面板相关
const quickSwitchVisible = ref<boolean>(false)
const quickSwitchSelectedIndex = ref<number>(0)
const quickSwitchInputRef = ref<HTMLInputElement | null>(null)
const quickSwitchShortcut = ref<KeyboardShortcut>({ key: 'k', ctrl: true })
const isCapturingShortcut = ref<boolean>(false)
const shortcutInputRef = ref<HTMLInputElement | null>(null)
const quickSwitchSearchQuery = ref<string>('')
// const keyboardCaptureOverlayRef = ref<HTMLDivElement | null>(null)

// 窗口管理器相关
const windowManagerContainerRef = ref<HTMLElement | null>(null)
const windowManagerWindows = ref<Map<string, WindowData>>(new Map())
const windowManagerCounter = ref(0)
const windowManagerIsDragging = ref(false)
const windowManagerDraggingWindowId = ref<string | null>(null)
const windowManagerHighlightedWindowId = ref<string | null>(null)
const windowManagerHoveredWindowId = ref<string | null>(null)
const windowManagerEditingWindowId = ref<string | null>(null)
const windowManagerEditUrlValue = ref('')
const windowManagerIsResizing = ref(false)
const windowManagerResizingWindowId = ref<string | null>(null)
const windowManagerContainerRect = ref({ width: 0, height: 0 })
const windowManagerHideIslandTimer = ref<number | null>(null)
const windowManagerLayoutVersion = ref(0) // 用于强制重新计算 resize handles

// 拖拽指示器
const windowManagerDragIndicator = ref({
  visible: false,
  x: 0,
  y: 0,
  width: 0,
  height: 0,
  title: ''
})

// 常量
const MIN_WINDOW_WIDTH = 120
const MIN_WINDOW_HEIGHT = 120

// 从 localStorage 加载折叠状态
const historyCollapsed = ref<boolean>((() => {
  try {
    const saved = localStorage.getItem('historyCollapsed')
    return saved === 'true'
  } catch {
    return false
  }
})())
const edgeDetectionThreshold = 5 // 边缘检测阈值（像素）
let hideSidebarTimer: number | null = null // 隐藏侧边栏的定时器
const sidebarKey = ref<number>(0) // 用于强制重新渲染侧边栏，重置transform

// SDK实例和应用状态订阅
const lzcsdk = new lzcAPIGateway()
let appChangeSubscription: { unsubscribe: () => void } | null = null

// 获取应用列表的函数
const fetchAppList = async () => {
  try {
    const response = await lzcsdk.pkgm.QueryApplication({})
    if (response?.infoList) {
      apps.value = response.infoList as AppInfo[]
      // 默认显示当前域名
      if (!currentApp.value) {
        apps.value.unshift({
          appid: 'current',
          title: '当前应用',
          description: `当前域名: ${currentDomain.value}`,
          icon: '',
          domain: currentDomain.value,
          status: 4,
          instanceStatus: 4
        })
      }
    }
  } catch (error) {
    console.error('获取应用列表失败:', error)
  }
}

// 浮动按钮位置管理
// 计算默认右下角位置（按钮尺寸 56x56px，留出边距）
const getDefaultPosition = () => ({
  x: window.innerWidth - 76,  // 56px + 20px 边距
  y: window.innerHeight - 76
})
const expandBtnPosition = ref(getDefaultPosition()) // 默认右下角
const isDragging = ref(false)
const isMouseDown = ref(false) // 鼠标是否按下
const dragStart = ref({ x: 0, y: 0 })

/**
 * 转拼音（支持全拼和首字母）
 */
const toPinyinForms = (text: string): { full: string; abbr: string } => {
  try {
    const pyArr = pinyin(text, { style: pinyin.STYLE_NORMAL })
    const full = pyArr.flat().join("").toLowerCase()
    const abbr = pyArr.map(p => p[0][0]).join("").toLowerCase()
    return { full, abbr }
  } catch (e) {
    return { full: '', abbr: '' }
  }
}

// 检查应用是否正在运行（status === 4 且 instanceStatus === 4）
// status: 4 表示应用已安装
// instanceStatus: 4 表示运行中, 1 表示已停止
const isRunning = (app: AppInfo): boolean => {
  return app.status === 4 && app.instanceStatus === 4
}

// 排序应用：正在运行的排在最前面
const sortedApps = computed(() => {
  const running = apps.value.filter(isRunning)
  const notRunning = apps.value.filter(app => !isRunning(app))
  return [...running, ...notRunning]
})

// 过滤和搜索应用
const filteredApps = computed(() => {
  let result = sortedApps.value
  
  if (!searchQuery.value) return result
  
  const keyword = searchQuery.value.toLowerCase().trim()
  if (!keyword) return result
  
  return result.filter(app => {
    const title = app.title || app.domain
    
    // 1. 文字匹配搜索（标题）
    const titleLower = title.toLowerCase()
    if (titleLower.includes(keyword)) {
      return true
    }
    
    // 2. 域名匹配
    const domainLower = app.domain.toLowerCase()
    if (domainLower.includes(keyword)) {
      return true
    }
    
    // 3. appid匹配
    const appidLower = (app.appid || '').toLowerCase()
    if (appidLower.includes(keyword)) {
      return true
    }
    
    // 4. 拼音搜索（首字母和全拼）
    try {
      const titlePinyin = toPinyinForms(title)
      // 首字母检索（模糊匹配）
      if (titlePinyin.abbr.includes(keyword)) {
        return true
      }
      // 全拼检索（模糊匹配）
      if (titlePinyin.full.includes(keyword)) {
        return true
      }
    } catch (e) {
      // 如果拼音转换失败，忽略拼音搜索
    }
    
    return false
  })
})

const currentApp = computed(() => {
  return apps.value.find(app => app.domain === currentDomain.value)
})


// 统计正在运行的应用数量
const runningCount = computed(() => {
  return apps.value.filter(isRunning).length
})

// 统计已安装的应用数量
const installedCount = computed(() => {
  return apps.value.filter(app => app.status === 4).length
})

// 快捷切换面板中的应用列表（排除当前应用，并补充完整的应用信息，支持搜索）
const quickSwitchApps = computed(() => {
  let result = appHistory.value
    .filter(app => app.domain !== currentAppDomain.value)
    .map(app => {
      // 从 apps 列表中查找完整的应用信息
      const fullApp = apps.value.find(a => a.appid === app.appid || a.domain === app.domain)
      return fullApp || app
    })
  
  // 搜索过滤（使用和侧边栏一样的搜索逻辑）
  if (quickSwitchSearchQuery.value) {
    const keyword = quickSwitchSearchQuery.value.toLowerCase().trim()
    if (keyword) {
      result = result.filter(app => {
        const title = app.title || app.domain
        
        // 1. 文字匹配搜索（标题）
        const titleLower = title.toLowerCase()
        if (titleLower.includes(keyword)) {
          return true
        }
        
        // 2. 域名匹配
        const domainLower = app.domain.toLowerCase()
        if (domainLower.includes(keyword)) {
          return true
        }
        
        // 3. appid匹配
        const appidLower = (app.appid || '').toLowerCase()
        if (appidLower.includes(keyword)) {
          return true
        }
        
        // 4. 拼音搜索（首字母和全拼）
        try {
          const titlePinyin = toPinyinForms(title)
          // 首字母检索（模糊匹配）
          if (titlePinyin.abbr.includes(keyword)) {
            return true
          }
          // 全拼检索（模糊匹配）
          if (titlePinyin.full.includes(keyword)) {
            return true
          }
        } catch (e) {
          // 如果拼音转换失败，忽略拼音搜索
        }
        
        return false
      })
    }
  }
  
  return result
})

const openApp = async (app: AppInfo, skipCurrentDomainCheck = false) => {
  if (!skipCurrentDomainCheck && app.domain === currentDomain.value) {
    // 如果是当前应用，不打开
    return
  }
  
  // 如果传入的应用对象缺少完整信息（比如从历史记录中点击），从 apps 中查找完整信息
  let fullApp = app
  if (!app.title || !app.status) {
    const foundApp = apps.value.find(a => a.domain === app.domain || a.appid === app.appid)
    if (foundApp) {
      fullApp = foundApp
    }
  }
  
  const domain = fullApp.domain
  const url = getAppUrl(domain)
  
  // 根据窗口模式选择不同的处理方式
  if (windowMode.value === 'multi') {
    // 多应用模式：使用窗口管理器
    // 检查是否已经存在该窗口
    const existingWindow = Array.from(windowManagerWindows.value.values()).find(w => w.domain === domain)
    if (existingWindow) {
      // 如果窗口已存在，不重复创建
      return
    }
    
    // 检查窗口数量限制
    if (windowManagerWindows.value.size >= 4) {
      alert('最多支持4个窗口')
      return
    }
    
    // 创建新窗口
    windowManagerCounter.value++
    const windowId = `window-${windowManagerCounter.value}`
    const tileIndex = windowManagerWindows.value.size as TileIndex
    
    const newWindow: WindowData = {
      id: windowId,
      title: fullApp.title || domain,
      url: url,
      domain: domain,
      tileIndex: tileIndex,
      isDragging: false,
      x: 0,
      y: 0,
      width: 0,
      height: 0
    }
    
    windowManagerWindows.value.set(windowId, newWindow)
    
    // 添加到历史记录
    appHistory.value = await addToHistory(fullApp, appHistory.value)
    
    // 确保容器大小已初始化，然后应用布局
    await nextTick()
    initWindowManagerContainerSize()
    // 再次等待 DOM 更新
    await nextTick()
    // 最后一次确保布局应用正确（包括响应式数据）
    applyWindowManagerLayout()
  } else {
    // 单应用模式：原有逻辑
    // 如果是新应用，添加到已打开列表
    if (!openedApps.value.includes(domain)) {
      openedApps.value.push(domain)
    }
    
    // 添加到历史记录（使用工具函数，自动保存到minidb）
    // 注意：saveAppHistory 会只保存必要字段（appid、icon、domain），忽略其他字段
    appHistory.value = await addToHistory(fullApp, appHistory.value)
    
    // 更新当前应用
    currentAppDomain.value = domain
  }
  
  // 点击应用后自动收起侧边栏
  sidebarCollapsed.value = true
}

// 处理应用点击事件：检测 Ctrl/Cmd 键，决定是在当前页面打开还是新标签页打开
const handleAppClick = async (event: MouseEvent, app: AppInfo) => {
  // 检测是否按住了 Ctrl 键（Windows/Linux）或 Cmd 键（Mac）
  const isCtrlClick = event.ctrlKey || event.metaKey
  
  if (isCtrlClick) {
    // Ctrl+点击：在新标签页打开
    event.preventDefault()
    event.stopPropagation()
    
    // 如果传入的应用对象缺少完整信息，从 apps 中查找完整信息
    let fullApp = app
    if (!app.title || !app.status) {
      const foundApp = apps.value.find(a => a.domain === app.domain || a.appid === app.appid)
      if (foundApp) {
        fullApp = foundApp
      }
    }
    
    const domain = fullApp.domain
    const url = getAppUrl(domain)
    
    // 在新标签页打开
    window.open(url, '_blank')
    
    // 仍然添加到历史记录（因为用户访问了应用）
    appHistory.value = await addToHistory(fullApp, appHistory.value)
  } else {
    // 普通点击：在当前页面打开（原有行为）
    await openApp(app)
  }
}

const toggleSidebar = (event?: Event) => {
  // 阻止事件冒泡，避免触发 handleClickOutside
  if (event) {
    event.stopPropagation()
  }
  sidebarCollapsed.value = !sidebarCollapsed.value
}

// 当侧边栏位置改变时，强制重新渲染
watch(sidebarPositions, () => {
  sidebarKey.value++
}, { deep: true })

watch(sidebarPosition, () => {
  sidebarKey.value++
})

// 当窗口模式改变时，初始化容器大小（如果需要）
watch(windowMode, (newMode) => {
  if (newMode === 'multi') {
    nextTick(() => {
      initWindowManagerContainerSize()
    })
  }
})

// 初始化窗口管理器容器大小
const initWindowManagerContainerSize = () => {
  if (windowManagerContainerRef.value) {
    const rect = windowManagerContainerRef.value.getBoundingClientRect()
    windowManagerContainerRect.value = { width: rect.width, height: rect.height }
    applyWindowManagerLayout()
  }
}

// 切换侧边栏位置（多选，确保至少保留一个）
const toggleSidebarPosition = async (position: SidebarPosition) => {
  const index = sidebarPositions.value.indexOf(position)
  if (index > -1) {
    // 如果要禁用，需要确保至少保留一个位置
    if (sidebarPositions.value.length > 1) {
      sidebarPositions.value.splice(index, 1)
    }
  } else {
    // 启用新位置
    sidebarPositions.value.push(position)
  }
  
  // 更新当前显示位置（如果当前位置被禁用，切换到第一个启用的位置）
  if (!sidebarPositions.value.includes(sidebarPosition.value)) {
    sidebarPosition.value = sidebarPositions.value[0]
  }
  
  // 用户主动修改设置，保存到 minidb
  await saveSidebarPositions([...sidebarPositions.value])
}

// 切换窗口模式
const setWindowMode = async (mode: WindowMode) => {
  if (windowMode.value === mode) return

  windowMode.value = mode
  // 用户主动修改设置，保存到 minidb
  await saveWindowMode(mode)
}

// 切换设置面板显示
const toggleSettings = () => {
  settingsVisible.value = !settingsVisible.value
  // 关闭设置面板时，停止快捷键捕获
  if (!settingsVisible.value) {
    isCapturingShortcut.value = false
  }
}

// 格式化快捷键显示
const formatShortcut = (shortcut: KeyboardShortcut): string => {
  const parts: string[] = []
  if (shortcut.ctrl) parts.push('Ctrl')
  if (shortcut.meta) parts.push('Meta')
  if (shortcut.shift) parts.push('Shift')
  if (shortcut.alt) parts.push('Alt')
  if (shortcut.key) {
    // 格式化按键名称
    let keyName = shortcut.key
    if (keyName.length === 1) {
      keyName = keyName.toUpperCase()
    } else {
      // 特殊按键名称映射
      const keyMap: Record<string, string> = {
        'ArrowUp': '↑',
        'ArrowDown': '↓',
        'ArrowLeft': '←',
        'ArrowRight': '→',
        'Enter': 'Enter',
        'Escape': 'Esc',
        'Space': 'Space',
        'Tab': 'Tab',
        'Backspace': 'Backspace',
        'Delete': 'Delete'
      }
      keyName = keyMap[keyName] || keyName
    }
    parts.push(keyName)
  }
  return parts.join(' + ')
}

// 开始捕获快捷键
const startCapturingShortcut = () => {
  isCapturingShortcut.value = true
  nextTick(() => {
    if (shortcutInputRef.value) {
      shortcutInputRef.value.focus()
    }
  })
}

// 停止捕获快捷键
const stopCapturingShortcut = () => {
  isCapturingShortcut.value = false
}

// 处理快捷键捕获
const handleShortcutCapture = (event: KeyboardEvent) => {
  if (!isCapturingShortcut.value) return
  
  event.preventDefault()
  event.stopPropagation()
  
  // 忽略功能键单独按下
  if (['Control', 'Meta', 'Shift', 'Alt'].includes(event.key)) {
    return
  }
  
  // 构建快捷键配置
  const shortcut: KeyboardShortcut = {
    key: event.key,
    ctrl: event.ctrlKey,
    shift: event.shiftKey,
    alt: event.altKey,
    meta: event.metaKey
  }
  
  // 至少需要一个修饰键（Ctrl、Shift、Alt、Meta）
  if (!shortcut.ctrl && !shortcut.shift && !shortcut.alt && !shortcut.meta) {
    return
  }
  
  // 更新快捷键
  quickSwitchShortcut.value = shortcut
  isCapturingShortcut.value = false
  
  // 保存到设置
  saveQuickSwitchShortcut(shortcut).catch(err => {
    console.error('保存快捷键设置失败:', err)
  })
}

// 清空设置
const handleClearSettings = async () => {
  if (confirm('确定要清空所有设置吗？这将重置侧边栏位置和窗口模式为默认值。')) {
    try {
      await clearSettings()
      // 重置为默认值
      sidebarPositions.value = ['left']
      sidebarPosition.value = 'left'
      windowMode.value = 'single'
      // 重新加载设置（会创建默认记录并更新缓存）
      const defaultSettings = await loadSettings()
      // 确保界面同步
      sidebarPositions.value = defaultSettings.sidebarPositions
      sidebarPosition.value = defaultSettings.sidebarPositions[0] || 'left'
      windowMode.value = defaultSettings.windowMode
      alert('设置已清空')
    } catch (error) {
      console.error('清空设置失败:', error)
      alert('清空设置失败，请重试')
    }
  }
}

// ==================== 窗口管理器辅助函数 ====================
const EPSILON = 0.5

const approxEqual = (a: number, b: number, tolerance = EPSILON) => Math.abs(a - b) <= tolerance

const getWindowManagerElement = (id: string): HTMLElement | null => {
  if (typeof window === 'undefined') return null
  return document.querySelector(`[data-window-id="${id}"]`) as HTMLElement | null
}

const getAllWindowManagerWindowsArray = () => Array.from(windowManagerWindows.value.values())

// 从 DOM 读取窗口位置和大小
const getWindowManagerRect = (win: WindowData) => {
  const element = getWindowManagerElement(win.id)
  if (!element || !windowManagerContainerRef.value) return null
  const rect = element.getBoundingClientRect()
  const containerRect = windowManagerContainerRef.value.getBoundingClientRect()
  return {
    x: rect.left - containerRect.left,
    y: rect.top - containerRect.top,
    width: rect.width,
    height: rect.height
  }
}

const findWindowManagerColumnPeers = (win: WindowData) => {
  const container = windowManagerContainerRef.value
  if (!container) return []
  const winRect = getWindowManagerRect(win)
  if (!winRect) return []
  
  const left = winRect.x
  const right = winRect.x + winRect.width
  // 包括当前窗口本身
  return getAllWindowManagerWindowsArray().filter(other => {
    const otherRect = getWindowManagerRect(other)
    if (!otherRect) return false
    // 使用更大的容差来处理浮点数精度问题
    return approxEqual(otherRect.x, left, 1.0) && approxEqual(otherRect.x + otherRect.width, right, 1.0)
  })
}

const findWindowManagerColumnAfter = (win: WindowData) => {
  const container = windowManagerContainerRef.value
  if (!container) return []
  const winRect = getWindowManagerRect(win)
  if (!winRect) return []
  
  const boundary = winRect.x + winRect.width
  return getAllWindowManagerWindowsArray().filter(other => {
    if (other.id === win.id) return false
    const otherRect = getWindowManagerRect(other)
    if (!otherRect) return false
    // 使用更大的容差来处理浮点数精度问题
    return approxEqual(otherRect.x, boundary, 1.0)
  })
}

const findWindowManagerRowPeers = (win: WindowData) => {
  const container = windowManagerContainerRef.value
  if (!container) return []
  const winRect = getWindowManagerRect(win)
  if (!winRect) return []
  
  const top = winRect.y
  const bottom = winRect.y + winRect.height
  // 包括当前窗口本身
  return getAllWindowManagerWindowsArray().filter(other => {
    const otherRect = getWindowManagerRect(other)
    if (!otherRect) return false
    // 使用更大的容差来处理浮点数精度问题
    return approxEqual(otherRect.y, top, 1.0) && approxEqual(otherRect.y + otherRect.height, bottom, 1.0)
  })
}

const findWindowManagerRowBelow = (win: WindowData) => {
  const container = windowManagerContainerRef.value
  if (!container) return []
  const winRect = getWindowManagerRect(win)
  if (!winRect) return []
  
  const boundary = winRect.y + winRect.height
  return getAllWindowManagerWindowsArray().filter(other => {
    if (other.id === win.id) return false
    const otherRect = getWindowManagerRect(other)
    if (!otherRect) return false
    // 使用更大的容差来处理浮点数精度问题
    return approxEqual(otherRect.y, boundary, 1.0)
  })
}

const getWindowManagerAtPosition = (x: number, y: number): WindowData | null => {
  for (const win of windowManagerWindows.value.values()) {
    const element = getWindowManagerElement(win.id)
    if (!element) continue
    const rect = element.getBoundingClientRect()
    if (x >= rect.left && x <= rect.right && y >= rect.top && y <= rect.bottom) {
      return win
    }
  }
  return null
}

// ==================== 窗口管理器布局计算 ====================

const calculateWindowManagerLayout = (windowCount: number): Layout => {
  let { width, height } = windowManagerContainerRect.value
  
  // 如果容器大小未初始化，使用窗口大小作为后备
  if (width === 0 || height === 0) {
    width = window.innerWidth
    height = window.innerHeight
  }
  
  if (windowCount === 0) {
    return { cols: 1, rows: 1, tiles: [] }
  }
  
  if (windowCount === 1) {
    return {
      cols: 1,
      rows: 1,
      tiles: [{
        index: 0 as TileIndex,
        x: 0,
        y: 0,
        width,
        height
      }]
    }
  }
  
  if (windowCount === 2) {
    return {
      cols: 2,
      rows: 1,
      tiles: [
        { index: 0 as TileIndex, x: 0, y: 0, width: width / 2, height },
        { index: 1 as TileIndex, x: width / 2, y: 0, width: width / 2, height }
      ]
    }
  }
  
  if (windowCount === 3) {
    // 左侧一个，右侧两个（上下分布）
    return {
      cols: 2,
      rows: 2,
      tiles: [
        { index: 0 as TileIndex, x: 0, y: 0, width: width / 2, height },
        { index: 1 as TileIndex, x: width / 2, y: 0, width: width / 2, height: height / 2 },
        { index: 2 as TileIndex, x: width / 2, y: height / 2, width: width / 2, height: height / 2 }
      ]
    }
  }
  
  // 4个窗口：2x2 网格
  return {
    cols: 2,
    rows: 2,
    tiles: [
      { index: 0 as TileIndex, x: 0, y: 0, width: width / 2, height: height / 2 },
      { index: 1 as TileIndex, x: width / 2, y: 0, width: width / 2, height: height / 2 },
      { index: 2 as TileIndex, x: 0, y: height / 2, width: width / 2, height: height / 2 },
      { index: 3 as TileIndex, x: width / 2, y: height / 2, width: width / 2, height: height / 2 }
    ]
  }
}

// 应用布局到窗口（使用 CSS 绝对定位，不更新响应式数据）
const applyWindowManagerLayout = (useTransition = false) => {
  if (windowManagerIsDragging.value || windowManagerIsResizing.value) return
  
  const windowCount = windowManagerWindows.value.size
  const layout = calculateWindowManagerLayout(windowCount)
  const container = windowManagerContainerRef.value
  if (!container) return
  
  // 直接操作 DOM，使用 CSS 绝对定位更新位置和大小（不触发 Vue 重新渲染）
  windowManagerWindows.value.forEach((win) => {
    const tile = layout.tiles.find(t => t.index === win.tileIndex)
    if (tile) {
      const element = getWindowManagerElement(win.id)
      if (!element) return
      
      // 获取当前元素的实际位置（从 DOM 读取）
      const currentRect = element.getBoundingClientRect()
      const containerRect = container.getBoundingClientRect()
      const currentX = currentRect.left - containerRect.left
      const currentY = currentRect.top - containerRect.top
      
      // 计算需要移动的距离
      const deltaX = tile.x - currentX
      const deltaY = tile.y - currentY
      const deltaWidth = tile.width - currentRect.width
      const deltaHeight = tile.height - currentRect.height
      
      // 如果有位置或大小变化，使用 CSS transition 实现平滑动画
      if (useTransition && (Math.abs(deltaX) > 0.1 || Math.abs(deltaY) > 0.1 || Math.abs(deltaWidth) > 0.1 || Math.abs(deltaHeight) > 0.1)) {
        // 设置 transition
        element.style.transition = 'left 0.3s ease-out, top 0.3s ease-out, width 0.3s ease-out, height 0.3s ease-out'
        
        // 更新位置和大小
        element.style.left = `${tile.x}px`
        element.style.top = `${tile.y}px`
        element.style.width = `${tile.width}px`
        element.style.height = `${tile.height}px`
        
        // 动画完成后清除 transition
        setTimeout(() => {
          element.style.transition = ''
        }, 300)
      } else {
        // 没有动画，直接更新
        element.style.left = `${tile.x}px`
        element.style.top = `${tile.y}px`
        element.style.width = `${tile.width}px`
        element.style.height = `${tile.height}px`
      }
      
      // 更新响应式数据（用于其他逻辑判断）
      win.x = tile.x
      win.y = tile.y
      win.width = tile.width
      win.height = tile.height
    }
  })
  
  // 增加布局版本号，触发 resize handles 重新计算
  windowManagerLayoutVersion.value++
}

// 获取窗口管理器窗口列表（不排序，保持插入顺序，避免因排序改变导致 DOM 重新排列）
const windowManagerVisibleWindows = computed(() => {
  // 添加 layoutVersion 依赖，确保布局变化时重新渲染
  const _ = windowManagerLayoutVersion.value
  return Array.from(windowManagerWindows.value.values())
})

// 获取窗口样式（只返回基础样式，位置和大小由 CSS 直接控制）
const getWindowManagerWindowStyle = (_win: WindowData) => {
  // 只返回基础样式，位置和大小通过直接操作 DOM 的 style 属性来更新
  // 这样不会触发 Vue 重新渲染
  return {
    position: 'absolute' as const,
    display: 'flex' as const
  }
}

// 获取拖拽指示器样式
const getWindowManagerDragIndicatorStyle = () => {
  return {
    left: `${windowManagerDragIndicator.value.x}px`,
    top: `${windowManagerDragIndicator.value.y}px`,
    width: `${windowManagerDragIndicator.value.width}px`,
    height: `${windowManagerDragIndicator.value.height}px`
  }
}

// ==================== 窗口管理器鼠标进入/离开处理 ====================
// 鼠标进入窗口
const handleWindowManagerMouseEnter = (win: WindowData) => {
  if (windowManagerIsDragging.value || windowManagerIsResizing.value) return
  
  // 清除隐藏定时器
  if (windowManagerHideIslandTimer.value) {
    clearTimeout(windowManagerHideIslandTimer.value)
    windowManagerHideIslandTimer.value = null
  }
  
  // 显示灵动岛
  windowManagerHoveredWindowId.value = win.id
}

// 鼠标离开窗口
const handleWindowManagerMouseLeave = (windowId: string) => {
  if (
    windowManagerHoveredWindowId.value === windowId &&
    !windowManagerIsDragging.value &&
    !windowManagerIsResizing.value &&
    windowManagerEditingWindowId.value !== windowId
  ) {
    // 延迟隐藏，避免快速移动时闪烁
    if (!windowManagerHideIslandTimer.value) {
      windowManagerHideIslandTimer.value = window.setTimeout(() => {
        if (
          windowManagerHoveredWindowId.value === windowId &&
          windowManagerEditingWindowId.value !== windowId
        ) {
          windowManagerHoveredWindowId.value = null
        }
        windowManagerHideIslandTimer.value = null
      }, 150) // 150ms 延迟
    }
  }
}

// ==================== 窗口管理器URL编辑和刷新 ====================
const focusWindowManagerUrlEditorInput = (windowId: string) => {
  nextTick(() => {
    const input = document.querySelector(`[data-url-editor="${windowId}"]`) as HTMLInputElement | null
    if (input) {
      input.focus()
      input.select()
    }
  })
}

const cancelWindowManagerUrlEdit = () => {
  windowManagerEditUrlValue.value = ''
  windowManagerEditingWindowId.value = null
}

const commitWindowManagerUrlEdit = () => {
  if (!windowManagerEditingWindowId.value) return
  const win = windowManagerWindows.value.get(windowManagerEditingWindowId.value)
  if (!win) {
    cancelWindowManagerUrlEdit()
    return
  }

  const nextUrl = windowManagerEditUrlValue.value.trim()
  if (nextUrl.length > 0) {
    win.url = nextUrl
  }

  cancelWindowManagerUrlEdit()
  windowManagerHoveredWindowId.value = win.id
}

const toggleWindowManagerUrlEditor = (win: WindowData) => {
  if (windowManagerEditingWindowId.value === win.id) {
    cancelWindowManagerUrlEdit()
    return
  }

  windowManagerEditingWindowId.value = win.id
  windowManagerEditUrlValue.value = win.url
  windowManagerHoveredWindowId.value = win.id
  focusWindowManagerUrlEditorInput(win.id)
}

const handleWindowManagerUrlInputChange = (event: Event) => {
  windowManagerEditUrlValue.value = (event.target as HTMLInputElement).value
}

const handleWindowManagerUrlInputKeydown = (event: KeyboardEvent) => {
  if (event.key === 'Enter') {
    event.preventDefault()
    commitWindowManagerUrlEdit()
  } else if (event.key === 'Escape') {
    event.preventDefault()
    cancelWindowManagerUrlEdit()
  }
}

const refreshWindowManagerWindow = (windowId: string) => {
  const win = windowManagerWindows.value.get(windowId)
  if (!win) return
  
  nextTick(() => {
    const iframe = document.querySelector(`[data-window-id="${windowId}"] iframe`) as HTMLIFrameElement | null
    if (iframe) {
      const currentUrl = win.url
      iframe.src = ''
      setTimeout(() => {
        iframe.src = currentUrl
      }, 10)
    }
  })
}

const removeWindowManagerWindow = (windowId: string) => {
  windowManagerWindows.value.delete(windowId)
  
  if (windowManagerEditingWindowId.value === windowId) {
    cancelWindowManagerUrlEdit()
  }

  // 重新分配 tileIndex
  const remainingWindows = Array.from(windowManagerWindows.value.values()).sort((a, b) => a.tileIndex - b.tileIndex)
  remainingWindows.forEach((win, index) => {
    win.tileIndex = index as TileIndex
  })
  
  nextTick(() => {
    // 初始化窗口位置（使用 CSS 直接设置，不更新响应式数据）
    // applyWindowManagerLayout 会处理所有窗口的位置，包括新窗口
    applyWindowManagerLayout()
  })
}

// ==================== 窗口管理器拖拽功能 ====================
interface ResizeTarget {
  id: string
  element: HTMLElement
  initialX: number
  initialY: number
  initialWidth: number
  initialHeight: number
}

const handleWindowManagerIslandPointerDown = (e: PointerEvent, win: WindowData) => {
  // 如果点击的是按钮，不触发拖动
  const target = e.target as HTMLElement
  if (target.closest('.island-button') || target.closest('.island-input')) {
    return
  }

  if (windowManagerIsDragging.value || windowManagerIsResizing.value) {
    e.preventDefault()
    return
  }

  e.preventDefault()
  e.stopPropagation()

  const island = e.currentTarget as HTMLElement | null
  const container = windowManagerContainerRef.value
  if (!island || !container) return

  // 清除隐藏定时器
  if (windowManagerHideIslandTimer.value) {
    clearTimeout(windowManagerHideIslandTimer.value)
    windowManagerHideIslandTimer.value = null
  }

  windowManagerHoveredWindowId.value = win.id
  if (windowManagerEditingWindowId.value) {
    cancelWindowManagerUrlEdit()
  }

  const pointerId = e.pointerId
  const containerRect = container.getBoundingClientRect()
  
  // 从 DOM 读取窗口位置，避免依赖响应式数据
  const windowElement = getWindowManagerElement(win.id)
  if (!windowElement) return
  const windowRect = windowElement.getBoundingClientRect()
  const winX = windowRect.left - containerRect.left
  const winY = windowRect.top - containerRect.top
  const winWidth = windowRect.width
  
  const offsetX = e.clientX - (containerRect.left + winX)
  const offsetY = e.clientY - (containerRect.top + winY)

  windowManagerIsDragging.value = true
  windowManagerDraggingWindowId.value = win.id
  win.isDragging = true

  windowManagerDragIndicator.value = {
    visible: true,
    x: winX,
    y: winY,
    width: winWidth,
    height: 40,
    title: win.title
  }

  document.body.style.userSelect = 'none'
  document.body.style.pointerEvents = 'none'
  document.body.style.cursor = 'move'
  container.style.pointerEvents = 'auto'

  const updateIndicator = (clientX: number, clientY: number) => {
    const newX = clientX - containerRect.left - offsetX
    const newY = clientY - containerRect.top - offsetY
    windowManagerDragIndicator.value.x = newX
    windowManagerDragIndicator.value.y = newY

    const targetWin = getWindowManagerAtPosition(clientX, clientY)
    if (targetWin && targetWin.id !== win.id) {
      windowManagerHighlightedWindowId.value = targetWin.id
    } else {
      windowManagerHighlightedWindowId.value = null
    }
  }

  island.setPointerCapture(pointerId)
  updateIndicator(e.clientX, e.clientY)

  const onPointerMove = (ev: PointerEvent) => {
    if (ev.pointerId !== pointerId) return
    ev.preventDefault()
    updateIndicator(ev.clientX, ev.clientY)
  }

  const finishDrag = (ev: PointerEvent) => {
    if (ev.pointerId !== pointerId) return
    ev.preventDefault()
    ev.stopPropagation()

    island.removeEventListener('pointermove', onPointerMove)
    island.removeEventListener('pointerup', finishDrag)
    island.removeEventListener('pointercancel', finishDrag)

    if (island.hasPointerCapture(pointerId)) {
      island.releasePointerCapture(pointerId)
    }

    const wasDragging = windowManagerIsDragging.value
    const hadTarget = !!windowManagerHighlightedWindowId.value
    const targetWinId = windowManagerHighlightedWindowId.value

    windowManagerIsDragging.value = false
    windowManagerDraggingWindowId.value = null
    win.isDragging = false

    // 清除高亮状态
    windowManagerHighlightedWindowId.value = null
    windowManagerDragIndicator.value.visible = false
    windowManagerHoveredWindowId.value = null

    document.body.style.userSelect = ''
    document.body.style.pointerEvents = ''
    document.body.style.cursor = ''
    container.style.pointerEvents = ''

    if (wasDragging) {
      if (hadTarget && targetWinId) {
        // 有目标窗口，交换位置
        const targetWin = windowManagerWindows.value.get(targetWinId)
        if (targetWin) {
          // 交换 tileIndex
          const tempIndex = win.tileIndex
          win.tileIndex = targetWin.tileIndex
          targetWin.tileIndex = tempIndex
          
          // 从 DOM 读取当前位置和大小（保留手动调整的结果）
          const winElement = getWindowManagerElement(win.id)
          const targetElement = getWindowManagerElement(targetWin.id)
          
          if (winElement && targetElement) {
            const containerRect = container.getBoundingClientRect()
            const winRect = winElement.getBoundingClientRect()
            const targetRect = targetElement.getBoundingClientRect()
            
            const winCurrentX = winRect.left - containerRect.left
            const winCurrentY = winRect.top - containerRect.top
            const winCurrentWidth = winRect.width
            const winCurrentHeight = winRect.height
            
            const targetCurrentX = targetRect.left - containerRect.left
            const targetCurrentY = targetRect.top - containerRect.top
            const targetCurrentWidth = targetRect.width
            const targetCurrentHeight = targetRect.height
            
            // 设置 transition
            winElement.style.transition = 'left 0.3s ease-out, top 0.3s ease-out, width 0.3s ease-out, height 0.3s ease-out'
            targetElement.style.transition = 'left 0.3s ease-out, top 0.3s ease-out, width 0.3s ease-out, height 0.3s ease-out'
            
            // 交换位置（使用对方当前的位置和大小）
            winElement.style.left = `${targetCurrentX}px`
            winElement.style.top = `${targetCurrentY}px`
            winElement.style.width = `${targetCurrentWidth}px`
            winElement.style.height = `${targetCurrentHeight}px`
            
            targetElement.style.left = `${winCurrentX}px`
            targetElement.style.top = `${winCurrentY}px`
            targetElement.style.width = `${winCurrentWidth}px`
            targetElement.style.height = `${winCurrentHeight}px`
            
            // 更新响应式数据（用于其他逻辑判断）
            win.x = targetCurrentX
            win.y = targetCurrentY
            win.width = targetCurrentWidth
            win.height = targetCurrentHeight
            
            targetWin.x = winCurrentX
            targetWin.y = winCurrentY
            targetWin.width = winCurrentWidth
            targetWin.height = winCurrentHeight
            
            // 动画完成后清除 transition 并增加版本号
            setTimeout(() => {
              winElement.style.transition = ''
              targetElement.style.transition = ''
              // 增加版本号，触发 resize handles 重新计算
              windowManagerLayoutVersion.value++
            }, 300)
          }
        }
      } else {
        // 没有交换，恢复原位置（使用动画）
        nextTick(() => {
          applyWindowManagerLayout(true)
        })
      }
    }
  }

  island.addEventListener('pointermove', onPointerMove)
  island.addEventListener('pointerup', finishDrag)
  island.addEventListener('pointercancel', finishDrag)
}

// ==================== 窗口管理器调整大小功能 ====================
// 这些函数需要读取响应式数据，Vue 会自动追踪依赖
const canWindowManagerResizeRight = (win: WindowData): boolean => {
  // 触发响应式依赖（确保窗口数量、位置等变化时重新计算）
  const windowCount = windowManagerWindows.value.size
  // 添加 layoutVersion 依赖，确保布局变化时重新计算
  const _ = windowManagerLayoutVersion.value
  if (windowCount < 2) return false
  
  // 从 DOM 读取当前状态
  const result = findWindowManagerColumnAfter(win)
  return result.length > 0
}

const canWindowManagerResizeBottom = (win: WindowData): boolean => {
  // 触发响应式依赖
  const windowCount = windowManagerWindows.value.size
  // 添加 layoutVersion 依赖，确保布局变化时重新计算
  const _ = windowManagerLayoutVersion.value
  if (windowCount < 2) return false
  
  // 从 DOM 读取当前状态
  const result = findWindowManagerRowBelow(win)
  return result.length > 0
}

const handleWindowManagerResizePointerDown = (e: PointerEvent, win: WindowData, edge: 'right' | 'bottom') => {
  if (windowManagerIsResizing.value) {
    e.preventDefault()
    return
  }

  e.preventDefault()
  e.stopPropagation()

  const handle = e.currentTarget as HTMLElement | null
  const container = windowManagerContainerRef.value
  if (!handle || !container) return

  if (windowManagerEditingWindowId.value) {
    cancelWindowManagerUrlEdit()
  }

  const buildTargets = (items: WindowData[]): ResizeTarget[] | null => {
    const targets: ResizeTarget[] = []
    const containerRect = container.getBoundingClientRect()
    for (const item of items) {
      const element = getWindowManagerElement(item.id)
      if (!element) {
        return null
      }
      // 从 DOM 读取初始位置和大小，而不是从响应式数据读取
      const rect = element.getBoundingClientRect()
      targets.push({
        id: item.id,
        element,
        initialX: rect.left - containerRect.left,
        initialY: rect.top - containerRect.top,
        initialWidth: rect.width,
        initialHeight: rect.height
      })
    }
    return targets
  }

  const pointerId = e.pointerId

  const cleanupCommon = () => {
    windowManagerIsResizing.value = false
    windowManagerResizingWindowId.value = null
    document.body.style.userSelect = ''
    document.body.style.pointerEvents = ''
    document.body.style.cursor = ''
    container.style.pointerEvents = ''
  }

  if (edge === 'right') {
    const columnTargets = buildTargets(findWindowManagerColumnPeers(win))
    const rightColumnTargets = buildTargets(findWindowManagerColumnAfter(win))

    if (!columnTargets || columnTargets.length === 0 || !rightColumnTargets || rightColumnTargets.length === 0) {
      return
    }

    const maxPositive = Math.max(0, Math.min(...rightColumnTargets.map(t => t.initialWidth - MIN_WINDOW_WIDTH)))
    const maxNegative = Math.max(0, Math.min(...columnTargets.map(t => t.initialWidth - MIN_WINDOW_WIDTH)))
    const startX = e.clientX

    windowManagerIsResizing.value = true
    windowManagerResizingWindowId.value = win.id

    document.body.style.userSelect = 'none'
    document.body.style.pointerEvents = 'none'
    document.body.style.cursor = 'ew-resize'
    container.style.pointerEvents = 'auto'

    handle.setPointerCapture(pointerId)

    const onPointerMove = (ev: PointerEvent) => {
      if (ev.pointerId !== pointerId) return
      ev.preventDefault()

      let deltaX = ev.clientX - startX
      if (deltaX > 0) {
        deltaX = Math.min(deltaX, maxPositive)
      } else {
        deltaX = -Math.min(Math.abs(deltaX), maxNegative)
      }

      // 禁用 transition，确保调整大小实时响应
      columnTargets.forEach(target => {
        target.element.style.transition = 'none'
        const newWidth = Math.max(MIN_WINDOW_WIDTH, target.initialWidth + deltaX)
        target.element.style.width = `${newWidth}px`
      })

      rightColumnTargets.forEach(target => {
        target.element.style.transition = 'none'
        const newWidth = Math.max(MIN_WINDOW_WIDTH, target.initialWidth - deltaX)
        target.element.style.width = `${newWidth}px`
        target.element.style.left = `${target.initialX + deltaX}px`
      })
    }

    const finishResize = (ev: PointerEvent) => {
      if (ev.pointerId !== pointerId) return
      ev.preventDefault()
      ev.stopPropagation()

      handle.removeEventListener('pointermove', onPointerMove)
      handle.removeEventListener('pointerup', finishResize)
      handle.removeEventListener('pointercancel', finishResize)

      if (handle.hasPointerCapture(pointerId)) {
        handle.releasePointerCapture(pointerId)
      }

      // 恢复 transition（清除之前设置的 'none'）
      columnTargets.forEach(target => {
        target.element.style.transition = ''
      })
      rightColumnTargets.forEach(target => {
        target.element.style.transition = ''
      })

      // 注意：不更新响应式数据，位置和大小完全由 CSS 控制
      // 这样可以避免触发 Vue 重新渲染，防止 iframe 重新加载
      // 调整大小后，不调用 applyLayout，保持手动调整的状态

      cleanupCommon()
    }

    handle.addEventListener('pointermove', onPointerMove)
    handle.addEventListener('pointerup', finishResize)
    handle.addEventListener('pointercancel', finishResize)
    return
  }

  const rowTargets = buildTargets(findWindowManagerRowPeers(win))
  const lowerRowTargets = buildTargets(findWindowManagerRowBelow(win))

  if (!rowTargets || rowTargets.length === 0 || !lowerRowTargets || lowerRowTargets.length === 0) {
    return
  }

  const maxPositive = Math.max(0, Math.min(...lowerRowTargets.map(t => t.initialHeight - MIN_WINDOW_HEIGHT)))
  const maxNegative = Math.max(0, Math.min(...rowTargets.map(t => t.initialHeight - MIN_WINDOW_HEIGHT)))
  const startY = e.clientY

  windowManagerIsResizing.value = true
  windowManagerResizingWindowId.value = win.id

  document.body.style.userSelect = 'none'
  document.body.style.pointerEvents = 'none'
  document.body.style.cursor = 'ns-resize'
  container.style.pointerEvents = 'auto'

  handle.setPointerCapture(pointerId)

  const onPointerMove = (ev: PointerEvent) => {
    if (ev.pointerId !== pointerId) return
    ev.preventDefault()

    let deltaY = ev.clientY - startY
    if (deltaY > 0) {
      deltaY = Math.min(deltaY, maxPositive)
    } else {
      deltaY = -Math.min(Math.abs(deltaY), maxNegative)
    }

    // 禁用 transition，确保调整大小实时响应
    rowTargets.forEach(target => {
      target.element.style.transition = 'none'
      const newHeight = Math.max(MIN_WINDOW_HEIGHT, target.initialHeight + deltaY)
      target.element.style.height = `${newHeight}px`
    })

    lowerRowTargets.forEach(target => {
      target.element.style.transition = 'none'
      const newHeight = Math.max(MIN_WINDOW_HEIGHT, target.initialHeight - deltaY)
      target.element.style.height = `${newHeight}px`
      target.element.style.top = `${target.initialY + deltaY}px`
    })
  }

  const finishResize = (ev: PointerEvent) => {
    if (ev.pointerId !== pointerId) return
    ev.preventDefault()
    ev.stopPropagation()

    handle.removeEventListener('pointermove', onPointerMove)
    handle.removeEventListener('pointerup', finishResize)
    handle.removeEventListener('pointercancel', finishResize)

    if (handle.hasPointerCapture(pointerId)) {
      handle.releasePointerCapture(pointerId)
    }

    // 恢复 transition（清除之前设置的 'none'）
    rowTargets.forEach(target => {
      target.element.style.transition = ''
    })
    lowerRowTargets.forEach(target => {
      target.element.style.transition = ''
    })

    // 注意：不更新响应式数据，位置和大小完全由 CSS 控制
    // 这样可以避免触发 Vue 重新渲染，防止 iframe 重新加载
    // 调整大小后，不调用 applyLayout，保持手动调整的状态

    cleanupCommon()
  }

  handle.addEventListener('pointermove', onPointerMove)
  handle.addEventListener('pointerup', finishResize)
  handle.addEventListener('pointercancel', finishResize)
}

// 监听搜索框变化，移动端搜索时自动折叠最近应用列表
watch(searchQuery, (newQuery) => {
  // 只在移动端生效
  if (window.innerWidth <= 768) {
    if (newQuery && newQuery.trim()) {
      // 有搜索内容时，自动折叠
      historyCollapsed.value = true
    }
  }
})

// 监听折叠状态变化，保存到 localStorage
watch(historyCollapsed, (newValue) => {
  try {
    localStorage.setItem('historyCollapsed', String(newValue))
  } catch (e) {
    // localStorage 可能不可用，忽略错误
  }
})

// 处理鼠标移动，检测边缘悬浮
const handleMouseMove = (event: MouseEvent) => {
  // 如果侧边栏已经展开，不需要检测边缘
  if (!sidebarCollapsed.value) {
    return
  }
  
  // 如果鼠标在侧边栏或展开按钮上，不触发边缘检测
  const target = event.target as HTMLElement
  if (sidebarRef.value?.contains(target) || expandBtnRef.value?.contains(target)) {
    return
  }
  
  const x = event.clientX
  const y = event.clientY
  const windowWidth = window.innerWidth
  const windowHeight = window.innerHeight
  
  // 检测左侧边缘（排除顶部和底部区域，避免误触发）
  if (sidebarPositions.value.includes('left') && x <= edgeDetectionThreshold && y > 50 && y < windowHeight - 50) {
    // 鼠标移动到边缘时，自动聚焦主窗口，以便快捷键生效
    window.focus()
    
    sidebarPosition.value = 'left'
    sidebarCollapsed.value = false
    return
  }
  
  // 检测右侧边缘（排除顶部和底部区域，避免误触发）
  if (sidebarPositions.value.includes('right') && x >= windowWidth - edgeDetectionThreshold && y > 50 && y < windowHeight - 50) {
    // 鼠标移动到边缘时，自动聚焦主窗口，以便快捷键生效
    window.focus()
    
    sidebarPosition.value = 'right'
    sidebarCollapsed.value = false
    return
  }
  
  // 检测顶部边缘（排除左右两侧区域，避免误触发）
  if (sidebarPositions.value.includes('top') && y <= edgeDetectionThreshold && x > 50 && x < windowWidth - 50) {
    // 鼠标移动到边缘时，自动聚焦主窗口，以便快捷键生效
    window.focus()
    
    sidebarPosition.value = 'top'
    sidebarCollapsed.value = false
    return
  }
  
  // 检测底部边缘（排除左右两侧区域，避免误触发）
  if (sidebarPositions.value.includes('bottom') && y >= windowHeight - edgeDetectionThreshold && x > 50 && x < windowWidth - 50) {
    // 鼠标移动到边缘时，自动聚焦主窗口，以便快捷键生效
    window.focus()
    
    sidebarPosition.value = 'bottom'
    sidebarCollapsed.value = false
    return
  }
}

// 处理鼠标离开侧边栏 - 重构版本
const handleSidebarMouseLeave = () => {
  // 如果侧边栏已经收起，不需要处理
  if (sidebarCollapsed.value) {
    return
  }
  
  // 清除之前的定时器
  if (hideSidebarTimer) {
    clearTimeout(hideSidebarTimer)
  }
  
  // 延迟隐藏侧边栏
  hideSidebarTimer = window.setTimeout(() => {
    // 再次检查侧边栏状态
    if (!sidebarCollapsed.value) {
      sidebarCollapsed.value = true
    }
    hideSidebarTimer = null
  }, 200) // 200ms 延迟
}

// 处理鼠标进入侧边栏，取消隐藏定时器
const handleSidebarMouseEnter = () => {
  if (hideSidebarTimer) {
    clearTimeout(hideSidebarTimer)
    hideSidebarTimer = null
  }
}

// 处理点击外部区域收缩侧边栏
const handleClickOutside = (event: MouseEvent | TouchEvent) => {
  // 如果侧边栏已经收起，不需要处理
  if (sidebarCollapsed.value) {
    return
  }
  
  // 获取点击目标
  let target: HTMLElement | null = null
  if (event instanceof MouseEvent) {
    target = event.target as HTMLElement
  } else if (event instanceof TouchEvent) {
    // 触摸事件
    if (event.touches && event.touches.length > 0) {
      target = event.touches[0].target as HTMLElement
    } else if (event.changedTouches && event.changedTouches.length > 0) {
      target = event.changedTouches[0].target as HTMLElement
    }
  }
  
  if (!target) return
  
  // 检查点击目标是否在侧边栏内
  if (sidebarRef.value?.contains(target)) {
    return
  }
  
  // 检查点击目标是否是展开按钮（即使侧边栏收起时也可能存在）
  if (expandBtnRef.value?.contains(target)) {
    return
  }
  
  // 点击在外部，收缩侧边栏
  sidebarCollapsed.value = true
}

// 处理触摸外部区域收缩侧边栏（移动端）
const handleTouchOutside = (event: TouchEvent) => {
  handleClickOutside(event)
}

// 打开快捷切换面板
const openQuickSwitch = () => {
  // 只在桌面端、单应用模式下显示
  const isMobile = window.innerWidth <= 768
  if (isMobile || windowMode.value !== 'single') {
    return
  }
  
  // 即使appHistory为空也允许打开（因为历史记录可能还在加载中）
  quickSwitchVisible.value = true
  quickSwitchSelectedIndex.value = 0 // 默认聚焦第一个应用（排除当前应用后的第一个）
  quickSwitchSearchQuery.value = '' // 清空搜索
  
  // 等待 DOM 更新后聚焦输入框
  nextTick(() => {
    if (quickSwitchInputRef.value) {
      quickSwitchInputRef.value.focus()
      quickSwitchInputRef.value.select()
    }
  })
}

// 关闭快捷切换面板
const closeQuickSwitch = () => {
  quickSwitchVisible.value = false
  quickSwitchSelectedIndex.value = 0
  quickSwitchSearchQuery.value = ''
}

// 监听搜索输入变化，重置选中索引
watch(quickSwitchSearchQuery, () => {
  quickSwitchSelectedIndex.value = 0
})

// 覆盖层使用 pointer-events: none 让事件自然穿透到iframe
// 键盘事件通过全局window/document监听捕获
// 鼠标事件通过全局监听 + 坐标判断来记录日志

// 检查鼠标是否在覆盖层区域内
// const isMouseOverOverlay = (clientX: number, clientY: number): boolean => {
//   const overlay = keyboardCaptureOverlayRef.value
//   if (!overlay) return false
//   
//   const rect = overlay.getBoundingClientRect()
//   return (
//     clientX >= rect.left &&
//     clientX <= rect.right &&
//     clientY >= rect.top &&
//     clientY <= rect.bottom
//   )
// }

// 全局鼠标事件监听（用于调试，即使覆盖层设置了 pointer-events: none）
// const handleGlobalMouseMove = (event: MouseEvent) => {
//   if (!currentAppDomain.value) return
//   
//   if (isMouseOverOverlay(event.clientX, event.clientY)) {
//     console.log('[覆盖层调试] 鼠标移动（全局监听）:', {
//       clientX: event.clientX,
//       clientY: event.clientY,
//       target: event.target,
//       activeElement: document.activeElement,
//       overlayElement: keyboardCaptureOverlayRef.value,
//       isOverlayFocused: document.activeElement === keyboardCaptureOverlayRef.value
//     })
//   }
// }

// const handleGlobalMouseDown = (event: MouseEvent) => {
//   if (!currentAppDomain.value) return
//   
//   if (isMouseOverOverlay(event.clientX, event.clientY)) {
//     console.log('[覆盖层调试] mousedown事件（全局监听）:', {
//       clientX: event.clientX,
//       clientY: event.clientY,
//       target: event.target,
//       activeElement: document.activeElement
//     })
//   }
// }

// const handleGlobalMouseUp = (event: MouseEvent) => {
//   if (!currentAppDomain.value) return
//   
//   if (isMouseOverOverlay(event.clientX, event.clientY)) {
//     console.log('[覆盖层调试] mouseup事件（全局监听）:', {
//       clientX: event.clientX,
//       clientY: event.clientY,
//       target: event.target,
//       activeElement: document.activeElement
//     })
//   }
// }

// const handleGlobalClick = (event: MouseEvent) => {
//   if (!currentAppDomain.value) return
//   
//   if (isMouseOverOverlay(event.clientX, event.clientY)) {
//     console.log('[覆盖层调试] click事件（全局监听）:', {
//       clientX: event.clientX,
//       clientY: event.clientY,
//       target: event.target,
//       activeElement: document.activeElement
//     })
//   }
// }

// 为iframe设置事件监听器（仅同源iframe，跨域iframe由于浏览器安全策略无法拦截）
const setupIframeListeners = () => {
  // 为单应用模式的iframe添加监听
  if (windowMode.value === 'single') {
    iframeList.value.forEach(item => {
      const iframe = document.getElementById(item.id) as HTMLIFrameElement | null
      if (iframe) {
        // 检查是否已经添加过监听器
        if ((iframe as any).__keydownHandler) {
          console.log(`[快捷键初始化] iframe ${item.id} 已经设置了监听器，跳过`)
          return
        }
        
        try {
          // 尝试访问iframe的contentWindow（仅同源iframe可以）
          const iframeWindow = iframe.contentWindow
          if (iframeWindow) {
            console.log(`[快捷键初始化] 为iframe ${item.id} 添加键盘事件监听器`)
            
            // 在iframe的window上添加监听器
            const iframeHandler = (event: KeyboardEvent) => {
              console.log(`[快捷键调试] 收到来自iframe ${item.id} 的键盘事件:`, event)
              // 将事件传递给主处理函数
              handleKeyDown(event)
            }
            
            // 使用capture阶段和最高优先级
            iframeWindow.addEventListener('keydown', iframeHandler, { capture: true, passive: false })
            
            // 保存handler引用以便后续清理
            ;(iframe as any).__keydownHandler = iframeHandler
          }
        } catch (e) {
          // 跨域iframe会抛出异常，这是正常的
          // 由于浏览器同源策略，无法拦截跨域iframe内部的键盘事件
          console.warn(`[快捷键初始化] iframe ${item.id} 是跨域的，无法拦截其内部的键盘事件（浏览器安全限制）`)
        }
      }
    })
  }
  
  // 为多应用模式的iframe添加监听
  if (windowMode.value === 'multi') {
    windowManagerWindows.value.forEach((win, winId) => {
      const windowElement = document.querySelector(`[data-window-id="${winId}"]`) as HTMLElement | null
      if (windowElement) {
        const iframe = windowElement.querySelector('iframe') as HTMLIFrameElement | null
        if (iframe) {
          // 检查是否已经添加过监听器
          if ((iframe as any).__keydownHandler) {
            console.log(`[快捷键初始化] 窗口 ${winId} 的iframe已经设置了监听器，跳过`)
            return
          }
          
          try {
            const iframeWindow = iframe.contentWindow
            if (iframeWindow) {
              console.log(`[快捷键初始化] 为窗口 ${winId} 的iframe添加键盘事件监听器`)
              
              const iframeHandler = (event: KeyboardEvent) => {
                console.log(`[快捷键调试] 收到来自窗口 ${winId} iframe的键盘事件:`, event)
                handleKeyDown(event)
              }
              
              iframeWindow.addEventListener('keydown', iframeHandler, { capture: true, passive: false })
              ;(iframe as any).__keydownHandler = iframeHandler
            }
          } catch (e) {
            // 跨域iframe会抛出异常，这是正常的
            // 由于浏览器同源策略，无法拦截跨域iframe内部的键盘事件
            console.warn(`[快捷键初始化] 窗口 ${winId} 的iframe是跨域的，无法拦截其内部的键盘事件（浏览器安全限制）`)
          }
        }
      }
    })
  }
}

// 检查键盘事件是否匹配快捷键配置
const matchesShortcut = (event: KeyboardEvent, shortcut: KeyboardShortcut): boolean => {
  const keyMatches = event.key.toLowerCase() === shortcut.key.toLowerCase() || 
                      event.key === shortcut.key
  
  console.log('[快捷键匹配] 按键匹配检查:', {
    eventKey: event.key,
    shortcutKey: shortcut.key,
    keyMatches,
    eventKeyLower: event.key.toLowerCase(),
    shortcutKeyLower: shortcut.key.toLowerCase()
  })
  
  const ctrlMatches = shortcut.ctrl ? (event.ctrlKey || event.metaKey) : (!event.ctrlKey && !event.metaKey)
  const shiftMatches = shortcut.shift ? event.shiftKey : !event.shiftKey
  const altMatches = shortcut.alt ? event.altKey : !event.altKey
  const metaMatches = shortcut.meta ? event.metaKey : !event.metaKey
  
  console.log('[快捷键匹配] 修饰键检查:', {
    shortcut,
    eventCtrl: event.ctrlKey,
    eventMeta: event.metaKey,
    eventShift: event.shiftKey,
    eventAlt: event.altKey,
    ctrlMatches,
    shiftMatches,
    altMatches,
    metaMatches
  })
  
  // 如果配置了 ctrl，则允许 ctrl 或 meta（Mac 兼容）
  // 如果配置了 meta，则只允许 meta
  if (shortcut.ctrl) {
    const ctrlOrMeta = event.ctrlKey || event.metaKey
    const result = keyMatches && ctrlOrMeta && shiftMatches && altMatches
    console.log('[快捷键匹配] Ctrl模式结果:', result)
    return result
  }
  
  const result = keyMatches && ctrlMatches && shiftMatches && altMatches && metaMatches
  console.log('[快捷键匹配] 最终结果:', result)
  return result
}

// 快捷切换面板键盘导航（在全局 handleKeyDown 中调用）
const handleQuickSwitchKeyDown = (event: KeyboardEvent) => {
  if (!quickSwitchVisible.value) return false
  
  const apps = quickSwitchApps.value
  if (apps.length === 0) return false
  
  // 只处理特定的导航键，避免与其他快捷键冲突
  if (event.key === 'ArrowUp' || event.key.toLowerCase() === 'k') {
    // 如果按下了修饰键，不处理（可能是其他快捷键）
    if (event.ctrlKey || event.metaKey || event.shiftKey || event.altKey) {
      return false
    }
    event.preventDefault()
    event.stopPropagation()
    quickSwitchSelectedIndex.value = Math.max(0, quickSwitchSelectedIndex.value - 1)
    return true
  }
  
  if (event.key === 'ArrowDown' || event.key.toLowerCase() === 'j') {
    // 如果按下了修饰键，不处理（可能是其他快捷键）
    if (event.ctrlKey || event.metaKey || event.shiftKey || event.altKey) {
      return false
    }
    event.preventDefault()
    event.stopPropagation()
    quickSwitchSelectedIndex.value = Math.min(apps.length - 1, quickSwitchSelectedIndex.value + 1)
    return true
  }
  
  if (event.key === 'Enter') {
    // 如果按下了修饰键，不处理（可能是其他快捷键）
    if (event.ctrlKey || event.metaKey || event.shiftKey || event.altKey) {
      return false
    }
    event.preventDefault()
    event.stopPropagation()
    const selectedApp = apps[quickSwitchSelectedIndex.value]
    if (selectedApp) {
      openApp(selectedApp)
      closeQuickSwitch()
    }
    return true
  }
  
  if (event.key === 'Escape') {
    event.preventDefault()
    event.stopPropagation()
    closeQuickSwitch()
    return true
  }
  
  return false
}

// 处理键盘快捷键：Ctrl+S 或 Ctrl+Shift+F 聚焦搜索框（全局）
// 使用配置的快捷键打开快捷切换面板（仅桌面端、单应用模式）
const handleKeyDown = (event: KeyboardEvent) => {
  // 调试日志：记录所有键盘事件
  console.log('[快捷键调试] 收到键盘事件:', {
    key: event.key,
    code: event.code,
    ctrlKey: event.ctrlKey,
    metaKey: event.metaKey,
    shiftKey: event.shiftKey,
    altKey: event.altKey,
    target: event.target,
    currentTarget: event.currentTarget,
    isTrusted: event.isTrusted,
    type: event.type,
    phase: 'capture'
  })
  
  // 如果正在捕获快捷键，不处理其他快捷键
  if (isCapturingShortcut.value) {
    console.log('[快捷键调试] 正在捕获快捷键，跳过处理')
    return
  }
  
  // 检查是否匹配快捷切换面板的快捷键配置
  const matches = matchesShortcut(event, quickSwitchShortcut.value)
  console.log('[快捷键调试] 快捷键匹配检查:', {
    matches,
    configuredShortcut: quickSwitchShortcut.value,
    eventKey: event.key,
    eventCtrl: event.ctrlKey,
    eventMeta: event.metaKey
  })
  
  if (matches) {
    console.log('[快捷键调试] 匹配成功，准备处理')
    // 拦截浏览器默认行为和iframe内的默认行为
    event.preventDefault()
    event.stopPropagation()
    event.stopImmediatePropagation()
    
    const isMobile = window.innerWidth <= 768
    console.log('[快捷键调试] 环境检查:', {
      isMobile,
      windowMode: windowMode.value,
      quickSwitchVisible: quickSwitchVisible.value
    })
    
    if (!isMobile && windowMode.value === 'single') {
      if (quickSwitchVisible.value) {
        console.log('[快捷键调试] 关闭快捷切换面板')
        closeQuickSwitch()
      } else {
        console.log('[快捷键调试] 打开快捷切换面板')
        openQuickSwitch()
      }
      return
    } else {
      console.log('[快捷键调试] 环境不满足条件，不处理')
    }
  }
  
  // 如果快捷切换面板打开，处理面板内的键盘导航（在全局处理，防止被iframe拦截）
  if (quickSwitchVisible.value) {
    const handled = handleQuickSwitchKeyDown(event)
    if (handled) {
      return
    }
  }
  
  // Ctrl+S 或 Ctrl+Shift+F
  if ((event.ctrlKey || event.metaKey) && 
      (event.key === 's' || event.key === 'S' || 
       (event.shiftKey && (event.key === 'f' || event.key === 'F')))) {
    event.preventDefault()
    
    // 如果侧边栏关闭，先打开侧边栏
    if (sidebarCollapsed.value) {
      sidebarCollapsed.value = false
      // 等待侧边栏打开后再聚焦（使用 nextTick 确保 DOM 更新）
      nextTick(() => {
        if (searchInputRef.value) {
          searchInputRef.value.focus()
          searchInputRef.value.select()
        }
      })
    } else {
      // 侧边栏已打开，直接聚焦
      if (searchInputRef.value) {
        searchInputRef.value.focus()
        searchInputRef.value.select()
      }
    }
  }
}

onMounted(async () => {
  // 从 minidb 加载设置（强制重新加载，忽略缓存）
  try {
    const settings = await loadSettings(true)
    if (Array.isArray(settings.sidebarPositions) && settings.sidebarPositions.length > 0) {
      sidebarPositions.value = [...settings.sidebarPositions]
      sidebarPosition.value = sidebarPositions.value[0] || 'left'
    } else {
      sidebarPositions.value = ['left']
      sidebarPosition.value = 'left'
    }
    windowMode.value = settings.windowMode
    // 加载快捷键设置
    if (settings.quickSwitchShortcut) {
      quickSwitchShortcut.value = { ...settings.quickSwitchShortcut }
    }
  } catch (error) {
    console.error('加载设置失败:', error)
    sidebarPositions.value = ['left']
    sidebarPosition.value = 'left'
    windowMode.value = 'single'
    quickSwitchShortcut.value = { key: 'k', ctrl: true }
  }

  // 从 minidb 加载历史记录
  appHistory.value = await loadAppHistory()
  
  // 初始获取应用列表
  await fetchAppList()
  
  // 单应用模式下：自动打开最近打开的应用（使用历史记录中的第一个，因为已经按时间倒序排列）
  if (windowMode.value === 'single') {
    // 使用 appHistory 中的第一个应用（最近打开的）
    const lastOpenedApp = appHistory.value.length > 0 ? appHistory.value[0] : null
    if (lastOpenedApp && lastOpenedApp.domain !== currentDomain.value) {
      // 检查应用是否在列表中
      const appInList = apps.value.find(a => a.appid === lastOpenedApp.appid || a.domain === lastOpenedApp.domain)
      const appToOpen = appInList || lastOpenedApp
      
      // 直接打开应用，不保存到历史记录（因为已经在历史中了）
      const domain = appToOpen.domain
      if (!openedApps.value.includes(domain)) {
        openedApps.value.push(domain)
      }
      currentAppDomain.value = domain
    }
  }
  
  // 订阅应用状态变化
  try {
    const observable = lzcsdk.pkgm.SubscribeAppChange({})
    appChangeSubscription = observable.subscribe({
      next: (response) => {
        // 应用状态变化时，重新获取应用列表
        console.log('应用状态变化:', response)
        fetchAppList()
      },
      error: (error) => {
        console.error('订阅应用状态变化出错:', error)
      }
    })
  } catch (error) {
    console.error('订阅应用状态变化失败:', error)
  }
  
  // 添加全局点击监听和鼠标移动监听
  document.addEventListener('click', handleClickOutside)
  // 移动端触摸事件监听
  document.addEventListener('touchstart', handleTouchOutside, { passive: true })
  document.addEventListener('mousemove', handleMouseMove)
  
  // 添加全局鼠标事件监听（用于覆盖层调试，即使覆盖层设置了 pointer-events: none）
  // document.addEventListener('mousemove', handleGlobalMouseMove, { passive: true })
  // document.addEventListener('mousedown', handleGlobalMouseDown, { passive: true })
  // document.addEventListener('mouseup', handleGlobalMouseUp, { passive: true })
  // document.addEventListener('click', handleGlobalClick, { passive: true })
  // 添加键盘事件监听（使用最高优先级：window级别 + capture阶段 + 非passive）
  // 这样可以确保在事件传播的最早阶段捕获，即使iframe有焦点也能触发
  console.log('[快捷键初始化] 添加window级别监听器 (capture=true, 最高优先级)')
  window.addEventListener('keydown', handleKeyDown, { capture: true, passive: false })
  
  // 同时也在document上监听，作为备用
  console.log('[快捷键初始化] 添加document级别监听器 (capture=true, 最高优先级)')
  document.addEventListener('keydown', handleKeyDown, { capture: true, passive: false })
  
  // 为所有已存在的iframe添加事件监听（仅同源iframe，跨域iframe无法拦截）
  nextTick(() => {
    setupIframeListeners()
  })
  
  // 监听iframe的加载，为新加载的iframe添加事件监听
  watch(iframeList, () => {
    nextTick(() => {
      setupIframeListeners()
    })
  }, { deep: true })
  
  // 添加展开按钮拖动监听（使用passive: false以支持preventDefault）
  document.addEventListener('mousemove', handleExpandBtnMouseMove, { passive: false })
  document.addEventListener('mouseup', handleExpandBtnMouseUp, { passive: false })
  document.addEventListener('touchmove', handleExpandBtnTouchMove, { passive: false })
  document.addEventListener('touchend', handleExpandBtnTouchEnd, { passive: false })
  
  // 窗口大小改变时，调整按钮位置，确保按钮不会超出可视区域
  // 同时更新窗口管理器容器大小和布局
  const handleResize = () => {
    const maxX = window.innerWidth - 76  // 56px + 20px 边距
    const maxY = window.innerHeight - 76
    expandBtnPosition.value = {
      x: Math.max(20, Math.min(expandBtnPosition.value.x, maxX)),
      y: Math.max(20, Math.min(expandBtnPosition.value.y, maxY))
    }
    
    // 如果处于多窗口模式，更新窗口管理器容器大小并重新应用布局
    if (windowMode.value === 'multi' && windowManagerContainerRef.value) {
      const rect = windowManagerContainerRef.value.getBoundingClientRect()
      windowManagerContainerRect.value = { width: rect.width, height: rect.height }
      applyWindowManagerLayout()
    }
  }
  window.addEventListener('resize', handleResize)
  
  // 保存handleResize引用以便在onUnmounted中移除
  ;(window as any).__handleResize = handleResize
  
  // 窗口管理器容器大小监听（延迟初始化，确保容器已渲染）
  nextTick(() => {
    if (windowManagerContainerRef.value) {
      const resizeObserver = new ResizeObserver((entries) => {
        for (const entry of entries) {
          const { width, height } = entry.contentRect
          // 更新容器大小
          windowManagerContainerRect.value = { width, height }
          // 如果处于多窗口模式，重新应用布局
          if (windowMode.value === 'multi') {
            applyWindowManagerLayout()
          }
        }
      })
      resizeObserver.observe(windowManagerContainerRef.value)
      
      // 初始化容器大小
      initWindowManagerContainerSize()
      
      // 保存引用以便在onUnmounted中移除
      ;(windowManagerContainerRef.value as any).__resizeObserver = resizeObserver
    }
  })
})

onUnmounted(() => {
  // 移除全局监听
  document.removeEventListener('click', handleClickOutside)
  document.removeEventListener('touchstart', handleTouchOutside)
  document.removeEventListener('mousemove', handleMouseMove)
  document.removeEventListener('mousemove', handleExpandBtnMouseMove)
  
  // 移除全局鼠标事件监听（覆盖层调试）
  // document.removeEventListener('mousemove', handleGlobalMouseMove)
  // document.removeEventListener('mousedown', handleGlobalMouseDown)
  // document.removeEventListener('mouseup', handleGlobalMouseUp)
  // document.removeEventListener('click', handleGlobalClick)
  document.removeEventListener('mouseup', handleExpandBtnMouseUp)
  document.removeEventListener('touchmove', handleExpandBtnTouchMove)
  document.removeEventListener('touchend', handleExpandBtnTouchEnd)
  // 移除键盘事件监听
  console.log('[快捷键清理] 移除所有键盘事件监听器')
  window.removeEventListener('keydown', handleKeyDown, { capture: true } as any)
  document.removeEventListener('keydown', handleKeyDown, { capture: true } as any)
  
  // 清理iframe上的监听器
  iframeList.value.forEach(item => {
    const iframe = document.getElementById(item.id) as HTMLIFrameElement | null
    if (iframe) {
      try {
        const iframeWindow = iframe.contentWindow
        const handler = (iframe as any).__keydownHandler
        if (iframeWindow && handler) {
          iframeWindow.removeEventListener('keydown', handler, { capture: true } as any)
          delete (iframe as any).__keydownHandler
        }
      } catch (e) {
        // 跨域iframe无法访问
      }
    }
  })
  
  // 取消应用状态变化订阅
  if (appChangeSubscription) {
    appChangeSubscription.unsubscribe()
    appChangeSubscription = null
  }
  
  // 移除resize监听器
  const handleResize = (window as any).__handleResize
  if (handleResize) {
    window.removeEventListener('resize', handleResize)
    delete (window as any).__handleResize
  }
  
  // 清除定时器
  if (hideSidebarTimer) {
    clearTimeout(hideSidebarTimer)
  }
  
  // 清除灵动岛隐藏定时器
  if (windowManagerHideIslandTimer.value) {
    clearTimeout(windowManagerHideIslandTimer.value)
  }
})

const getAppUrl = (domain: string) => {
  const protocol = window.location.protocol
  return `${protocol}//${domain}`
}

// 生成 iframe 列表，每个应用对应一个独立的 iframe
const iframeList = computed(() => {
  return openedApps.value.map(domain => ({
    domain,
    src: getAppUrl(domain),
    id: `iframe-${domain}`
  }))
})


// ==================== 浮动按钮拖动和点击处理 ====================
// 记录按下时的初始位置
const dragStartPos = ref({ x: 0, y: 0 })
const hasMoved = ref(false)

const startButtonDrag = (clientX: number, clientY: number) => {
  isMouseDown.value = true
  hasMoved.value = false
  dragStart.value = {
    x: clientX - expandBtnPosition.value.x,
    y: clientY - expandBtnPosition.value.y
  }
  dragStartPos.value = { x: clientX, y: clientY }
  
  // 在拖动期间禁用iframe的pointer-events，防止iframe捕获鼠标事件
  document.body.classList.add('dragging-float-btn')
}

const handleButtonDrag = (clientX: number, clientY: number) => {
  if (!isMouseDown.value) return
  
  // 计算移动距离
  const deltaX = Math.abs(clientX - dragStartPos.value.x)
  const deltaY = Math.abs(clientY - dragStartPos.value.y)
  const distance = Math.sqrt(deltaX * deltaX + deltaY * deltaY)
  
  // 移动超过 3px 才视为拖动（降低阈值，提高响应性）
  if (distance > 3) {
    hasMoved.value = true
    isDragging.value = true
  }
  
  // 无论是否超过阈值，都立即更新位置，让拖动更跟手
  const newX = clientX - dragStart.value.x
  const newY = clientY - dragStart.value.y
  
  // 限制在可视区域内（按钮尺寸 56x56px，留出边距）
  const maxX = window.innerWidth - 76  // 56px + 20px 边距
  const maxY = window.innerHeight - 76
  
  expandBtnPosition.value = {
    x: Math.max(20, Math.min(newX, maxX)),
    y: Math.max(20, Math.min(newY, maxY))
  }
}

const endButtonDrag = () => {
  const wasDragging = hasMoved.value
  
  isMouseDown.value = false
  isDragging.value = false
  hasMoved.value = false
  
  // 恢复iframe的pointer-events
  document.body.classList.remove('dragging-float-btn')
  
  // 返回是否发生了拖动
  return wasDragging
}

// 鼠标事件
const handleExpandBtnMouseDown = (event: MouseEvent) => {
  if (event.button !== 0) return // 只处理左键
  startButtonDrag(event.clientX, event.clientY)
  // 只阻止默认行为，不阻止冒泡
  event.preventDefault()
}

const handleExpandBtnMouseMove = (event: MouseEvent) => {
  if (isMouseDown.value) {
    handleButtonDrag(event.clientX, event.clientY)
    if (hasMoved.value) {
      // 只在真正拖动时才阻止默认行为
      event.preventDefault()
    }
  }
}

const handleExpandBtnMouseUp = (event: MouseEvent) => {
  // 只有在按钮被按下时才处理释放事件
  if (!isMouseDown.value) return
  
  const wasDragging = endButtonDrag()
  
  // 如果没有拖动，视为点击
  if (!wasDragging) {
    toggleSidebar()
  }
  
  // 只在拖动时才阻止事件传播
  if (wasDragging) {
    event.preventDefault()
    event.stopPropagation()
  }
}

// 触摸事件
const handleExpandBtnTouchStart = (event: TouchEvent) => {
  if (event.touches.length !== 1) return
  const touch = event.touches[0]
  startButtonDrag(touch.clientX, touch.clientY)
  event.preventDefault()
}

const handleExpandBtnTouchMove = (event: TouchEvent) => {
  if (event.touches.length !== 1) return
  if (isMouseDown.value) {
    const touch = event.touches[0]
    handleButtonDrag(touch.clientX, touch.clientY)
    if (hasMoved.value) {
      event.preventDefault()
    }
  }
}

const handleExpandBtnTouchEnd = (event: TouchEvent) => {
  // 只有在按钮被按下时才处理释放事件
  if (!isMouseDown.value) return
  
  const wasDragging = endButtonDrag()
  
  // 如果没有拖动，视为点击
  if (!wasDragging) {
    toggleSidebar()
  }
  
  if (wasDragging) {
    event.preventDefault()
    event.stopPropagation()
  }
}

// 清空历史记录
const handleClearHistory = async () => {
  if (confirm('确定要清空所有历史记录吗？')) {
    await clearAppHistory()
    appHistory.value = []
    console.log('已清空历史记录')
  }
}

</script>

<template>
  <div class="app-container">
    <!-- 边缘检测层 - 用于在iframe上方检测鼠标移动 -->
    <div class="edge-detection-layer">
      <div class="edge-left"></div>
      <div class="edge-right"></div>
      <div class="edge-top"></div>
      <div class="edge-bottom"></div>
    </div>
    
    <!-- 移动端侧边栏打开时的遮罩层 - 用于捕获点击事件隐藏侧边栏 -->
    <div 
      v-if="!sidebarCollapsed" 
      class="sidebar-overlay-mobile"
      @click="sidebarCollapsed = true"
      @touchstart="sidebarCollapsed = true"
    ></div>
    
    <!-- 单应用模式：iframe占满整个屏幕 -->
    <div v-if="windowMode === 'single'" class="main-iframe-container">
      <!-- 占位符 -->
      <div v-if="!currentAppDomain" class="iframe-placeholder">
        <p>请从应用列表中选择应用</p>
      </div>
      
      <!-- 为所有已打开的应用渲染独立的iframe（使用CSS控制显示/隐藏） -->
      <template v-for="item in iframeList" :key="item.id">
        <iframe 
          :id="item.id"
          :src="item.src"
          frameborder="0"
          class="main-iframe"
          :class="{ 'iframe-active': item.domain === currentAppDomain, 'iframe-inactive': item.domain !== currentAppDomain }"
          @load="setupIframeListeners"
        ></iframe>
      </template>
      
      <!-- 键盘事件捕获覆盖层（10%透明灰色，用于视觉提示） -->
      <!-- 使用 pointer-events: none 让事件自然穿透到iframe（跨域iframe无法手动转发事件） -->
      <!-- 键盘事件通过全局window/document监听捕获 -->
      <!-- 鼠标事件通过全局监听 + 坐标判断来记录日志 -->
      <!-- <div 
        v-if="currentAppDomain"
        ref="keyboardCaptureOverlayRef"
        class="keyboard-capture-overlay"
      ></div> -->
    </div>
    
    <!-- 多应用模式：窗口管理器 -->
    <div 
      v-if="windowMode === 'multi'" 
      class="window-manager-container" 
      ref="windowManagerContainerRef"
    >
      <!-- 占位符 -->
      <div v-if="windowManagerWindows.size === 0" class="window-manager-placeholder">
        <p>请从应用列表中选择应用</p>
      </div>
      
      <!-- 窗口 -->
      <div
        v-for="win in windowManagerVisibleWindows"
        :key="win.id"
        :data-window-id="win.id"
        class="window-manager-window"
        :class="{ 
          'window-highlighted': windowManagerHighlightedWindowId === win.id,
          'window-dragging': win.isDragging,
          'window-hovered': windowManagerHoveredWindowId === win.id,
          'window-editing': windowManagerEditingWindowId === win.id
        }"
        :style="getWindowManagerWindowStyle(win)"
        @mouseenter="handleWindowManagerMouseEnter(win)"
        @mouseleave="handleWindowManagerMouseLeave(win.id)"
      >
        <!-- iOS灵动岛工具栏 -->
        <div
          class="window-island"
          :class="{ 
            'island-expanded': windowManagerEditingWindowId === win.id,
            'island-hovered': windowManagerHoveredWindowId === win.id
          }"
          @pointerdown="handleWindowManagerIslandPointerDown($event, win)"
        >
          <div class="island-content">
            <button
              v-if="windowManagerEditingWindowId !== win.id"
              class="island-button island-edit"
              type="button"
              @click.stop="toggleWindowManagerUrlEditor(win)"
              :aria-pressed="windowManagerEditingWindowId === win.id"
              title="编辑URL"
            >
              <svg width="10" height="10" viewBox="0 0 10 10" fill="none">
                <path d="M7.5 1.5L8.5 2.5L3 8H2V7L7.5 1.5Z" stroke="currentColor" stroke-width="1.2" stroke-linecap="round" stroke-linejoin="round"/>
              </svg>
            </button>
            <button
              v-if="windowManagerEditingWindowId !== win.id"
              class="island-button island-refresh"
              type="button"
              @click.stop="refreshWindowManagerWindow(win.id)"
              title="刷新窗口"
            >
              <svg width="10" height="10" viewBox="0 0 10 10" fill="none">
                <path d="M8.5 2.5C8 1.5 7 1 5.5 1C3.5 1 2 2.5 2 4.5M1.5 2.5L2 1.5L3 2.5M1.5 7.5C2 8.5 3 9 4.5 9C6.5 9 8 7.5 8 5.5M8.5 7.5L8 8.5L7 7.5" stroke="currentColor" stroke-width="1.2" stroke-linecap="round" stroke-linejoin="round"/>
              </svg>
            </button>
            <button
              v-if="windowManagerEditingWindowId !== win.id"
              class="island-button island-close"
              type="button"
              @click.stop="removeWindowManagerWindow(win.id)"
              title="关闭窗口"
            >
              <svg width="10" height="10" viewBox="0 0 10 10" fill="none">
                <circle cx="5" cy="5" r="4.5" stroke="currentColor" stroke-width="1.2" fill="none"/>
                <path d="M3.5 3.5L6.5 6.5M6.5 3.5L3.5 6.5" stroke="currentColor" stroke-width="1.2" stroke-linecap="round"/>
              </svg>
            </button>
          </div>

          <div
            class="island-editor"
            :class="{ 'island-editor-visible': windowManagerEditingWindowId === win.id }"
            @click.stop
          >
            <input
              :value="windowManagerEditUrlValue"
              class="island-input"
              type="text"
              placeholder="输入网址"
              :data-url-editor="win.id"
              @input="handleWindowManagerUrlInputChange"
              @keydown="handleWindowManagerUrlInputKeydown"
            />
            <button
              class="island-button island-action island-commit"
              type="button"
              @click.stop="commitWindowManagerUrlEdit"
              title="应用"
            >
              <svg width="10" height="10" viewBox="0 0 10 10" fill="none">
                <path d="M2 5L4.5 7.5L8 3" stroke="currentColor" stroke-width="1.2" stroke-linecap="round" stroke-linejoin="round"/>
              </svg>
            </button>
            <button
              class="island-button island-action island-cancel"
              type="button"
              @click.stop="cancelWindowManagerUrlEdit"
              title="取消"
            >
              <svg width="10" height="10" viewBox="0 0 10 10" fill="none">
                <path d="M2 2L8 8M8 2L2 8" stroke="currentColor" stroke-width="1.2" stroke-linecap="round"/>
              </svg>
            </button>
          </div>
        </div>
        
        <!-- 内容区 (iframe) -->
        <div class="window-manager-content">
          <iframe 
            :src="win.url" 
            frameborder="0"
            class="window-manager-iframe"
          ></iframe>
        </div>
        
        <!-- 调整大小的句柄 -->
        <div 
          v-if="canWindowManagerResizeRight(win)"
          class="resize-handle resize-handle-right"
          :data-resize-window="win.id"
          @pointerdown="handleWindowManagerResizePointerDown($event, win, 'right')"
        ></div>
        <div 
          v-if="canWindowManagerResizeBottom(win)"
          class="resize-handle resize-handle-bottom"
          :data-resize-window="win.id"
          @pointerdown="handleWindowManagerResizePointerDown($event, win, 'bottom')"
        ></div>
      </div>
      
      <!-- 拖拽指示器 -->
      <div 
        v-if="windowManagerDragIndicator.visible"
        class="drag-indicator"
        :style="getWindowManagerDragIndicatorStyle()"
      >
        {{ windowManagerDragIndicator.title }}
      </div>
    </div>

    <!-- 移动端遮罩层 -->
    <div 
      v-if="!sidebarCollapsed"
      class="sidebar-overlay"
      @click="toggleSidebar"
    ></div>

    <!-- 浮动应用列表 -->
    <div 
      :key="`sidebar-${sidebarPosition}-${sidebarKey}`"
      ref="sidebarRef" 
      class="floating-app-list" 
      :class="{ 
        'collapsed': sidebarCollapsed,
        [`position-${sidebarPosition}`]: true
      }"
      @mouseleave="handleSidebarMouseLeave"
      @mouseenter="handleSidebarMouseEnter"
    >
      <div class="app-list-header">
        <div class="header-top-row">
          <div class="search-box">
            <input 
              ref="searchInputRef"
              v-model="searchQuery" 
              type="text" 
              placeholder="搜索应用..." 
              class="search-input"
            />
          </div>
          
          <button @click.stop="toggleSettings" class="toggle-btn toggle-btn-settings" title="设置">
            <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
              <circle cx="12" cy="12" r="3"></circle>
              <path d="M12 2v2m0 16v2M4.93 4.93l1.41 1.41m11.32 11.32l1.41 1.41M2 12h2m16 0h2M4.93 19.07l1.41-1.41m11.32-11.32l1.41-1.41"></path>
            </svg>
          </button>
        </div>
        
        <!-- 历史应用（顶部/底部位置时显示在header中） -->
        <div v-if="appHistory.length > 0 && !sidebarCollapsed && (sidebarPosition === 'top' || sidebarPosition === 'bottom')" class="history-section">
          <div class="history-title-wrapper">
            <div class="history-title">最近使用</div>
            <button @click.stop="handleClearHistory" class="clear-history-btn" title="清空历史">
              <svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
                <line x1="18" y1="6" x2="6" y2="18"></line>
                <line x1="6" y1="6" x2="18" y2="18"></line>
              </svg>
            </button>
          </div>
          <div class="history-apps">
            <div 
              v-for="app in appHistory" 
              :key="app.appid"
              class="history-app-item"
              @click="handleAppClick($event, app)"
              :title="app.title || app.domain"
            >
              <img v-if="app.icon" :src="app.icon" :alt="app.title || app.domain" class="history-app-icon" />
              <div v-else class="history-app-icon-placeholder">{{ (app.title || app.domain)[0] }}</div>
            </div>
          </div>
        </div>
        
        <button @click.stop="toggleSidebar" class="toggle-btn toggle-btn-desktop">
          <svg v-if="sidebarCollapsed" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
            <line x1="3" y1="12" x2="21" y2="12"></line>
            <line x1="3" y1="6" x2="21" y2="6"></line>
            <line x1="3" y1="18" x2="21" y2="18"></line>
          </svg>
          <svg v-else width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
            <line x1="18" y1="6" x2="6" y2="18"></line>
            <line x1="6" y1="6" x2="18" y2="18"></line>
          </svg>
        </button>
      </div>
      
      <!-- 历史应用（左右位置时显示在header下方） -->
      <div v-if="appHistory.length > 0 && !sidebarCollapsed && (sidebarPosition === 'left' || sidebarPosition === 'right')" class="history-section">
        <div class="history-title-wrapper" :class="{ 'collapsed': historyCollapsed }" @click="historyCollapsed = !historyCollapsed">
          <div class="history-title">
            <span class="history-title-text-desktop">最近使用</span>
            <span class="history-title-text-mobile">最近应用</span>
            <span class="history-collapse-icon" :class="{ 'collapsed': historyCollapsed }">▼</span>
          </div>
          <button v-show="!historyCollapsed" @click.stop="handleClearHistory" class="clear-history-btn" title="清空历史">
            <svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
              <line x1="18" y1="6" x2="6" y2="18"></line>
              <line x1="6" y1="6" x2="18" y2="18"></line>
            </svg>
          </button>
        </div>
        <div v-show="!historyCollapsed" class="history-apps">
          <div 
            v-for="app in appHistory" 
            :key="app.appid"
            class="history-app-item"
            @click="handleAppClick($event, app)"
            :title="app.title || app.domain"
          >
            <img v-if="app.icon" :src="app.icon" :alt="app.title || app.domain" class="history-app-icon" />
            <div v-else class="history-app-icon-placeholder">{{ (app.title || app.domain)[0] }}</div>
          </div>
        </div>
      </div>

      <!-- 设置面板 -->
      <div v-if="!sidebarCollapsed && settingsVisible" class="settings-panel">
        <div class="settings-header">
          <div class="settings-title">设置</div>
          <button @click.stop="toggleSettings" class="settings-close-btn">
            <svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
              <line x1="18" y1="6" x2="6" y2="18"></line>
              <line x1="6" y1="6" x2="18" y2="18"></line>
            </svg>
          </button>
        </div>
        
        <div class="settings-content">
          <!-- 侧边栏位置设置 -->
          <div class="settings-section">
            <div class="settings-label">侧边栏位置（可多选）</div>
            <div class="settings-options">
              <label
                v-for="pos in ['left', 'right', 'top', 'bottom'] as SidebarPosition[]"
                :key="pos"
                class="settings-checkbox-label"
                :class="{ 'disabled': sidebarPositions.length === 1 && sidebarPositions.includes(pos) }"
              >
                <input
                  type="checkbox"
                  :checked="sidebarPositions.includes(pos)"
                  @change="toggleSidebarPosition(pos)"
                  :disabled="sidebarPositions.length === 1 && sidebarPositions.includes(pos)"
                  class="settings-checkbox"
                />
                <span>{{ pos === 'left' ? '左侧' : pos === 'right' ? '右侧' : pos === 'top' ? '顶部' : '底部' }}</span>
              </label>
            </div>
          </div>
          
          <!-- 窗口模式设置 -->
          <div class="settings-section">
            <div class="settings-label">窗口模式</div>
            <div class="settings-options">
              <button
                @click.stop="setWindowMode('single')"
                class="settings-option-btn"
                :class="{ 'active': windowMode === 'single' }"
              >
                单应用模式
              </button>
              <button
                @click.stop="setWindowMode('multi')"
                class="settings-option-btn"
                :class="{ 'active': windowMode === 'multi' }"
              >
                多应用模式
              </button>
            </div>
          </div>
          
          <!-- 快捷键设置 -->
          <div class="settings-section">
            <div class="settings-label">快捷切换面板快捷键</div>
            <div class="settings-options">
              <div class="shortcut-config">
                <input
                  ref="shortcutInputRef"
                  type="text"
                  class="shortcut-input"
                  :value="formatShortcut(quickSwitchShortcut)"
                  :placeholder="isCapturingShortcut ? '请按下快捷键...' : '点击设置快捷键'"
                  readonly
                  @focus="startCapturingShortcut"
                  @blur="stopCapturingShortcut"
                  @keydown="handleShortcutCapture"
                />
                <button
                  v-if="!isCapturingShortcut"
                  @click.stop="startCapturingShortcut"
                  class="shortcut-btn"
                >
                  设置
                </button>
                <button
                  v-else
                  @click.stop="stopCapturingShortcut"
                  class="shortcut-btn"
                >
                  取消
                </button>
              </div>
              <div class="shortcut-hint">
                提示：至少需要按下一个修饰键（Ctrl、Shift、Alt 或 Meta）
              </div>
            </div>
          </div>
          
          <!-- 清空设置 -->
          <div class="settings-section">
            <div class="settings-label">其他操作</div>
            <div class="settings-options">
              <button
                @click.stop="handleClearSettings"
                class="settings-clear-btn"
              >
                清空设置
              </button>
            </div>
          </div>
        </div>
      </div>

      <!-- 应用列表 -->
      <div v-if="!sidebarCollapsed && !settingsVisible" class="app-list-wrapper">
        <div class="app-list-title-section">
          <div class="app-list-title-text-desktop"></div>
          <div class="app-list-title-text-mobile">
            <span class="app-list-title-main">我的应用</span>
            <div class="app-list-stats">
              <span class="app-stat-item" title="正在运行">
                <span class="app-stat-icon">▶</span>
                <span class="app-stat-count">{{ runningCount }}</span>
              </span>
              <span class="app-stat-item" title="已安装">
                <span class="app-stat-icon">📦</span>
                <span class="app-stat-count">{{ installedCount }}</span>
              </span>
            </div>
          </div>
        </div>
        <div class="app-list-content">
          <div 
            v-for="app in filteredApps" 
            :key="app.appid"
            class="app-list-item"
            :class="{ 'active': app.domain === currentAppDomain, 'running': isRunning(app) }"
            @click="handleAppClick($event, app)"
          >
            <div class="app-list-icon-wrapper">
              <img v-if="app.icon" :src="app.icon" :alt="app.title || app.domain" class="app-list-icon" />
              <div v-else class="app-list-icon-placeholder">{{ (app.title || app.domain)[0] }}</div>
              <span v-if="isRunning(app)" class="running-badge"></span>
            </div>
            <span class="app-list-title">{{ app.title || app.domain }}</span>
          </div>
        </div>
      </div>
    </div>

    <!-- 侧边栏收起时的浮动按钮 -->
    <div 
      ref="expandBtnRef"
      v-if="sidebarCollapsed" 
      class="expand-btn"
      :class="{ 'is-dragging': isDragging }"
      :style="{ 
        left: `${expandBtnPosition.x}px`, 
        top: `${expandBtnPosition.y}px`
      }"
      @mousedown="handleExpandBtnMouseDown"
      @touchstart="handleExpandBtnTouchStart"
      title="点击打开侧边栏 / 拖动移动位置"
    >
      <svg 
        class="expand-btn-icon"
        width="24" 
        height="24" 
        viewBox="0 0 24 24" 
        fill="none"
      >
        <path d="M3 6h18M3 12h18M3 18h18" stroke="currentColor" stroke-width="2" stroke-linecap="round"/>
      </svg>
    </div>

    <!-- 快捷切换面板（仅桌面端、单应用模式） -->
    <div 
      v-if="quickSwitchVisible && windowMode === 'single'" 
      class="quick-switch-panel"
      @click.self="closeQuickSwitch"
    >
      <div class="quick-switch-content" @click.stop>
        <input
          ref="quickSwitchInputRef"
          v-model="quickSwitchSearchQuery"
          type="text"
          class="quick-switch-input"
          placeholder="搜索应用..."
        />
        <div class="quick-switch-apps">
          <div
            v-for="(app, index) in quickSwitchApps"
            :key="app.appid || app.domain"
            class="quick-switch-app-item"
            :class="{ 'selected': index === quickSwitchSelectedIndex }"
            @click="openApp(app); closeQuickSwitch()"
          >
            <img v-if="app.icon" :src="app.icon" :alt="app.title || app.domain" class="quick-switch-app-icon" />
            <div v-else class="quick-switch-app-icon-placeholder">{{ (app.title || app.domain)[0] }}</div>
            <span class="quick-switch-app-title">{{ app.title || app.domain }}</span>
          </div>
          <div v-if="quickSwitchApps.length === 0" class="quick-switch-empty">
            没有最近打开的应用
          </div>
        </div>
      </div>
    </div>
  </div>
</template>

<style scoped>
.app-container {
  width: 100%;
  height: 100%;
  overflow: hidden;
  position: relative;
}

/* 禁止整个界面文本选择，但 iframe 内的内容不受影响（iframe 是独立的文档） */
.app-container :deep(*) {
  user-select: none;
  -webkit-user-select: none;
  -moz-user-select: none;
  -ms-user-select: none;
}

/* 允许输入框和文本区域选择文本 */
.app-container :deep(input),
.app-container :deep(textarea),
.app-container :deep(.island-input) {
  user-select: text;
  -webkit-user-select: text;
  -moz-user-select: text;
  -ms-user-select: text;
}

/* iframe 内的内容不受影响（iframe 是独立的文档，样式不会穿透） */

/* 边缘检测层 - 在iframe上方，只在边缘区域可交互 */
.edge-detection-layer {
  position: fixed;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  z-index: 500;
  pointer-events: none;
}

.edge-detection-layer > div {
  position: absolute;
  pointer-events: auto;
  background: transparent;
}

/* 左侧边缘检测区域 */
.edge-left {
  top: 50px;
  left: 0;
  width: 10px;
  height: calc(100% - 100px);
}

/* 右侧边缘检测区域 */
.edge-right {
  top: 50px;
  right: 0;
  width: 10px;
  height: calc(100% - 100px);
}

/* 顶部边缘检测区域 */
.edge-top {
  top: 0;
  left: 50px;
  width: calc(100% - 100px);
  height: 10px;
}

/* 底部边缘检测区域 */
.edge-bottom {
  bottom: 0;
  left: 50px;
  width: calc(100% - 100px);
  height: 10px;
}

/* 移动端侧边栏打开时的遮罩层 */
.sidebar-overlay-mobile {
  display: none;
}

@media (max-width: 768px) {
  .sidebar-overlay-mobile {
    position: fixed;
    top: 0;
    left: 160px; /* 侧边栏宽度 */
    width: calc(100% - 160px);
    height: 100%;
    z-index: 999;
    background: transparent;
    pointer-events: auto;
    display: block;
  }
  
  /* 确保遮罩层不会遮挡侧边栏 */
  .floating-app-list.position-left {
    z-index: 1000;
  }
}

/* 主iframe容器 - 占满整个屏幕 */
.main-iframe-container {
  position: fixed;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  z-index: 1;
  background: white;
}

/* 窗口管理器容器 */
.window-manager-container {
  position: fixed;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  z-index: 1;
  background: white;
  overflow: visible;
}

.window-manager-placeholder {
  width: 100%;
  height: 100%;
  display: flex;
  align-items: center;
  justify-content: center;
  background: white;
  color: #999;
  font-size: 1.2rem;
}

/* 窗口管理器窗口 */
.window-manager-window {
  position: absolute;
  background: white;
  border: 1px solid #e0e0e0;
  display: flex;
  flex-direction: column;
  overflow: visible;
  transition: box-shadow 0.2s;
  will-change: transform;
  /* 移除可能影响 iframe 的 transform */
  transform: none;
}

.window-manager-content {
  flex: 1;
  overflow: hidden;
  background: transparent;
  position: relative;
}

.window-manager-iframe {
  width: 100%;
  height: 100%;
  border: none;
  display: block;
  pointer-events: auto;
  background: white;
}

/* 窗口管理器窗口状态 */
.window-manager-window.window-highlighted {
  border-color: #007acc;
  box-shadow: 0 0 10px rgba(0, 122, 204, 0.5);
}

.window-manager-window.window-dragging {
  opacity: 0.5;
}

/* iOS灵动岛样式 */
.window-island {
  position: absolute;
  top: 0;
  left: 50%;
  /* 初始状态：紧贴窗口顶部边缘，完全隐藏在顶部 */
  transform: translate(-50%, -100%);
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 4px 12px;
  max-width: calc(100% - 16px);
  background: rgba(37, 37, 38, 0.85);
  backdrop-filter: blur(20px);
  -webkit-backdrop-filter: blur(20px);
  border: 0.5px solid rgba(255, 255, 255, 0.1);
  border-radius: 0 0 16px 16px;
  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15), inset 0 0 0 0.5px rgba(255, 255, 255, 0.05);
  opacity: 0;
  pointer-events: none;
  cursor: move;
  /* 使用更流畅的动画曲线，增加动画时长 */
  transition: transform 0.35s cubic-bezier(0.34, 1.56, 0.64, 1), opacity 0.25s ease-out;
  z-index: 1000;
  white-space: nowrap;
}

.window-island.island-hovered,
.window-island.island-expanded {
  /* hover 时：从顶部边缘滑出，贴在窗口顶部 */
  opacity: 1;
  pointer-events: auto;
  transform: translate(-50%, 0);
}

.window-island.island-expanded {
  padding: 4px 14px;
  /* 编辑模式下稍微延长一点 */
  transition: transform 0.35s cubic-bezier(0.34, 1.56, 0.64, 1), opacity 0.25s ease-out, padding 0.2s ease;
}

.island-content {
  display: flex;
  align-items: center;
  gap: 8px;
  flex-shrink: 0;
}

.island-editor {
  display: flex;
  align-items: center;
  gap: 8px;
  max-width: 0;
  opacity: 0;
  overflow: hidden;
  transition: max-width 0.25s cubic-bezier(0.4, 0, 0.2, 1), opacity 0.25s ease;
  flex-shrink: 0;
}

.island-editor.island-editor-visible {
  max-width: 300px;
  opacity: 1;
}

.island-button {
  width: 28px;
  height: 20px;
  padding: 0;
  border: none;
  background: transparent;
  color: rgba(255, 255, 255, 0.7);
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: 4px;
  transition: background 0.15s ease, color 0.15s ease, transform 0.1s ease;
  flex-shrink: 0;
}

.island-button:hover {
  background: rgba(255, 255, 255, 0.1);
  color: rgba(255, 255, 255, 0.9);
}

.island-button:active {
  transform: scale(0.95);
}

.island-button svg {
  width: 16px;
  height: 16px;
  stroke: currentColor;
  stroke-width: 1.5;
}

.island-edit[aria-pressed='true'] {
  background: rgba(59, 124, 209, 0.2);
  color: rgba(59, 124, 209, 1);
}

.island-refresh:hover {
  background: rgba(76, 175, 80, 0.15);
  color: rgba(76, 175, 80, 1);
}

.island-close:hover {
  background: rgba(255, 82, 82, 0.15);
  color: rgba(255, 82, 82, 1);
}

.island-input {
  flex: 1;
  min-width: 0;
  height: 20px;
  padding: 0 10px;
  border: none;
  background: rgba(255, 255, 255, 0.08);
  color: rgba(255, 255, 255, 0.9);
  font-size: 12px;
  line-height: 1.2;
  border-radius: 4px;
  outline: none;
  transition: background 0.15s ease;
}

.island-input::placeholder {
  color: rgba(255, 255, 255, 0.4);
}

.island-input:focus {
  background: rgba(255, 255, 255, 0.12);
}

.island-action.island-commit:hover {
  background: rgba(59, 124, 209, 0.2);
  color: rgba(59, 124, 209, 1);
}

.island-action.island-cancel:hover {
  background: rgba(255, 82, 82, 0.15);
  color: rgba(255, 82, 82, 1);
}

/* 调整大小句柄 */
.resize-handle {
  position: absolute;
  background: transparent;
  z-index: 10;
  transition: background 0.15s;
}

.resize-handle-right {
  right: -6px;
  top: 0;
  bottom: 0;
  width: 12px;
  cursor: ew-resize;
}

.resize-handle-right::after {
  content: '';
  position: absolute;
  left: 50%;
  top: 0;
  bottom: 0;
  width: 2px;
  background: rgba(0, 122, 204, 0.3);
  transform: translateX(-50%);
  transition: background 0.15s;
}

.resize-handle-right:hover::after {
  background: #007acc;
  width: 3px;
}

.resize-handle-bottom {
  left: 0;
  right: 0;
  bottom: -6px;
  height: 12px;
  cursor: ns-resize;
}

.resize-handle-bottom::after {
  content: '';
  position: absolute;
  left: 0;
  right: 0;
  top: 50%;
  height: 2px;
  background: rgba(0, 122, 204, 0.3);
  transform: translateY(-50%);
  transition: background 0.15s;
}

.resize-handle-bottom:hover::after {
  background: #007acc;
  height: 3px;
}

.resize-handle:active::after {
  background: #00a8ff !important;
}

/* 拖拽指示器 */
.drag-indicator {
  position: absolute;
  background: rgba(0, 122, 204, 0.3);
  border: 2px dashed #007acc;
  color: #007acc;
  display: flex;
  align-items: center;
  justify-content: center;
  font-weight: bold;
  pointer-events: none;
  z-index: 1000;
  font-size: 14px;
}

.main-iframe {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  border: none;
  display: block;
  transition: transform 0.2s ease, width 0.2s ease, height 0.2s ease;
}

/* 激活的iframe - 正常显示 */
.iframe-active {
  z-index: 2;
  width: 100%;
  height: 100%;
  transform: translate(0, 0);
  pointer-events: auto;
}

/* 非激活的iframe - 通过CSS假隐藏（缩小并偏移到看不到的地方） */
.iframe-inactive {
  z-index: 1;
  width: 1px;
  height: 1px;
  transform: translate(-9999px, -9999px);
  pointer-events: none;
  overflow: hidden;
}

.iframe-placeholder {
  width: 100%;
  height: 100%;
  display: flex;
  align-items: center;
  justify-content: center;
  background: #f5f5f5;
  color: #999;
  font-size: 1.2rem;
}

/* 键盘事件捕获覆盖层 */
/* .keyboard-capture-overlay {
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  background: rgba(0, 0, 0, 0.1); 
  z-index: 100; 
  pointer-events: none; 
  outline: none; 
} */

/* 移动端遮罩层 - 默认隐藏 */
.sidebar-overlay {
  display: none;
}

/* 移动端显示遮罩 */
@media (max-width: 768px) {
  .sidebar-overlay {
    display: block;
    position: fixed;
    top: 0;
    left: 200px; /* 不覆盖侧边栏 */
    right: 0;
    bottom: 0;
    background: rgba(0, 0, 0, 0.5);
    z-index: 999;
    opacity: 1;
    animation: fadeIn 0.3s ease;
  }
  
  @keyframes fadeIn {
    from {
      opacity: 0;
    }
    to {
      opacity: 1;
    }
  }
}

@media (max-width: 480px) {
  .sidebar-overlay {
    left: 180px; /* 更小屏幕的侧边栏宽度 */
  }
}

/* 确保侧边栏在遮罩层上方 */
@media (max-width: 768px) {
  .floating-app-list {
    z-index: 1001 !important; /* 确保高于遮罩层（z-index: 999） */
  }
}

/* 浮动应用列表 */
.floating-app-list {
  position: fixed;
  background: rgba(255, 255, 255, 0.98);
  backdrop-filter: blur(24px);
  -webkit-backdrop-filter: blur(24px);
  z-index: 1000;
  display: flex;
  flex-direction: column;
  transition: transform 0.4s cubic-bezier(0.22, 0.61, 0.36, 1);
  overflow: hidden;
}

/* 左侧位置（默认） */
.floating-app-list.position-left {
  top: 0;
  left: 0;
  width: 340px;
  height: 100%;
  box-shadow: 4px 0 24px rgba(0, 0, 0, 0.08), 2px 0 8px rgba(0, 0, 0, 0.04);
  border-right: 1px solid rgba(0, 0, 0, 0.06);
  transform: translateX(0);
  transition: transform 0.4s cubic-bezier(0.22, 0.61, 0.36, 1);
}

/* 移动端：左侧侧边栏宽度减小 */
@media (max-width: 768px) {
  .floating-app-list.position-left {
    width: 200px;
  }
}

@media (max-width: 480px) {
  .floating-app-list.position-left {
    width: 180px;
  }
}

.floating-app-list.position-left.collapsed {
  transform: translateX(-100%);
  transition: transform 0.4s cubic-bezier(0.22, 0.61, 0.36, 1);
}

/* 右侧位置 */
.floating-app-list.position-right {
  top: 0;
  right: 0;
  width: 340px;
  height: 100%;
  box-shadow: -4px 0 24px rgba(0, 0, 0, 0.08), -2px 0 8px rgba(0, 0, 0, 0.04);
  border-left: 1px solid rgba(0, 0, 0, 0.06);
  transform: translateX(0);
  transition: transform 0.4s cubic-bezier(0.22, 0.61, 0.36, 1);
}

/* 移动端：右侧侧边栏宽度适配 */
@media (max-width: 768px) {
  .floating-app-list.position-right {
    width: 200px;
  }
}

@media (max-width: 480px) {
  .floating-app-list.position-right {
    width: 180px;
  }
}

.floating-app-list.position-right.collapsed {
  transform: translateX(100%);
  transition: transform 0.4s cubic-bezier(0.22, 0.61, 0.36, 1);
}

/* 顶部位置 */
.floating-app-list.position-top {
  top: 0;
  left: 0;
  width: 100%;
  height: 480px;
  box-shadow: 0 6px 28px rgba(0, 0, 0, 0.08), 0 2px 10px rgba(0, 0, 0, 0.04);
  flex-direction: column;
  border-bottom: 1px solid rgba(0, 0, 0, 0.08);
  transform: translateY(0);
  transition: transform 0.4s cubic-bezier(0.22, 0.61, 0.36, 1);
}

@media (max-width: 768px) {
  .floating-app-list.position-top {
    height: 60vh;
    max-height: 500px;
  }
}

@media (max-width: 480px) {
  .floating-app-list.position-top {
    height: 65vh;
  }
}

.floating-app-list.position-top .app-list-header {
  padding: 1rem 1.5rem;
  border-bottom: 1px solid #e8e8e8;
  background: linear-gradient(to bottom, #fafafa, #ffffff);
  display: flex;
  align-items: center;
  gap: 1rem;
  flex-wrap: wrap;
}

.floating-app-list.position-top .search-box {
  flex: 0 0 auto;
  width: 220px;
}

.floating-app-list.position-top .history-section {
  flex: 1;
  padding: 0;
  border-bottom: none;
  background: transparent;
  display: flex;
  align-items: center;
  gap: 0.75rem;
  min-width: 0;
}

.floating-app-list.position-top .history-title-wrapper {
  margin-bottom: 0;
  margin-right: 0.5rem;
  white-space: nowrap;
  font-size: 0.85rem;
  color: #666;
}

.floating-app-list.position-top .history-apps {
  display: flex;
  flex-direction: row;
  gap: 0.5rem;
  overflow-x: auto;
  flex: 1;
  min-width: 0;
}

.floating-app-list.position-top .app-list-content {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(90px, 1fr));
  grid-auto-rows: min-content;
  gap: 0.75rem;
  overflow-y: auto;
  overflow-x: hidden;
  padding: 1rem 1.5rem;
  flex: 1;
  max-height: calc(100% - 80px);
  /* 自定义滚动条样式 */
  scrollbar-width: thin;
  scrollbar-color: #c0c0c0 transparent;
}

.floating-app-list.position-top .app-list-content::-webkit-scrollbar {
  width: 6px;
}

.floating-app-list.position-top .app-list-content::-webkit-scrollbar-track {
  background: transparent;
}

.floating-app-list.position-top .app-list-content::-webkit-scrollbar-thumb {
  background: #c0c0c0;
  border-radius: 3px;
}

.floating-app-list.position-top .app-list-content::-webkit-scrollbar-thumb:hover {
  background: #a0a0a0;
}

.floating-app-list.position-top .app-list-item {
  flex-direction: column;
  align-items: center;
  width: 100%;
  padding: 0.75rem 0.5rem;
  border-radius: 12px;
  text-align: center;
  margin-bottom: 0;
  background: transparent;
  transition: all 0.2s;
  justify-self: center;
}

.floating-app-list.position-top .app-list-item:hover {
  background: #f5f5f5;
  transform: translateY(-2px);
}

.floating-app-list.position-top .app-list-icon-wrapper {
  margin-right: 0;
  margin-bottom: 0.5rem;
  width: 48px;
  height: 48px;
}

.floating-app-list.position-top .app-list-icon,
.floating-app-list.position-top .app-list-icon-placeholder {
  width: 48px;
  height: 48px;
  border-radius: 12px;
}

.floating-app-list.position-top .app-list-title {
  font-size: 0.8rem;
  line-height: 1.3;
  white-space: normal;
  word-break: break-word;
  display: -webkit-box;
  -webkit-line-clamp: 2;
  line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
  text-overflow: ellipsis;
}

.floating-app-list.position-top .history-app-item {
  flex-shrink: 0;
}

.floating-app-list.position-top.collapsed {
  transform: translateY(-100%);
  transition: transform 0.4s cubic-bezier(0.22, 0.61, 0.36, 1);
}

/* 底部位置 */
.floating-app-list.position-bottom {
  bottom: 0;
  left: 0;
  width: 100%;
  height: 480px;
  box-shadow: 0 -6px 28px rgba(0, 0, 0, 0.08), 0 -2px 10px rgba(0, 0, 0, 0.04);
  flex-direction: column;
  border-top: 1px solid rgba(0, 0, 0, 0.08);
  transform: translateY(0);
  transition: transform 0.4s cubic-bezier(0.22, 0.61, 0.36, 1);
}

@media (max-width: 768px) {
  .floating-app-list.position-bottom {
    height: 60vh;
    max-height: 500px;
  }
}

@media (max-width: 480px) {
  .floating-app-list.position-bottom {
    height: 65vh;
  }
}

.floating-app-list.position-bottom .app-list-header {
  padding: 1rem 1.5rem;
  border-top: 1px solid #e8e8e8;
  border-bottom: 1px solid #e8e8e8;
  background: linear-gradient(to top, #fafafa, #ffffff);
  order: 2;
  display: flex;
  align-items: center;
  gap: 1rem;
  flex-wrap: wrap;
}

.floating-app-list.position-bottom .search-box {
  flex: 0 0 auto;
  width: 220px;
}

.floating-app-list.position-bottom .history-section {
  flex: 1;
  padding: 0;
  border-top: none;
  border-bottom: none;
  background: transparent;
  order: 2;
  display: flex;
  align-items: center;
  gap: 0.75rem;
  min-width: 0;
}

.floating-app-list.position-bottom .history-title-wrapper {
  margin-bottom: 0;
  margin-right: 0.5rem;
  white-space: nowrap;
  font-size: 0.85rem;
  color: #666;
}

.floating-app-list.position-bottom .history-apps {
  display: flex;
  flex-direction: row;
  gap: 0.5rem;
  overflow-x: auto;
  flex: 1;
  min-width: 0;
}

.floating-app-list.position-bottom .app-list-content {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(90px, 1fr));
  grid-auto-rows: min-content;
  gap: 0.75rem;
  overflow-y: auto;
  overflow-x: hidden;
  padding: 1rem 1.5rem;
  flex: 1;
  max-height: calc(100% - 80px);
  order: 1;
  /* 自定义滚动条样式 */
  scrollbar-width: thin;
  scrollbar-color: #c0c0c0 transparent;
}

.floating-app-list.position-bottom .app-list-content::-webkit-scrollbar {
  width: 6px;
}

.floating-app-list.position-bottom .app-list-content::-webkit-scrollbar-track {
  background: transparent;
}

.floating-app-list.position-bottom .app-list-content::-webkit-scrollbar-thumb {
  background: #c0c0c0;
  border-radius: 3px;
}

.floating-app-list.position-bottom .app-list-content::-webkit-scrollbar-thumb:hover {
  background: #a0a0a0;
}

.floating-app-list.position-bottom .app-list-item {
  flex-direction: column;
  align-items: center;
  width: 100%;
  padding: 0.75rem 0.5rem;
  border-radius: 12px;
  text-align: center;
  margin-bottom: 0;
  background: transparent;
  transition: all 0.2s;
  justify-self: center;
}

.floating-app-list.position-bottom .app-list-item:hover {
  background: #f5f5f5;
  transform: translateY(2px);
}

.floating-app-list.position-bottom .app-list-icon-wrapper {
  margin-right: 0;
  margin-bottom: 0.5rem;
  width: 48px;
  height: 48px;
}

.floating-app-list.position-bottom .app-list-icon,
.floating-app-list.position-bottom .app-list-icon-placeholder {
  width: 48px;
  height: 48px;
  border-radius: 12px;
}

.floating-app-list.position-bottom .app-list-title {
  font-size: 0.8rem;
  line-height: 1.3;
  white-space: normal;
  word-break: break-word;
  display: -webkit-box;
  -webkit-line-clamp: 2;
  line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
  text-overflow: ellipsis;
}

.floating-app-list.position-bottom .history-app-item {
  flex-shrink: 0;
}

.floating-app-list.position-bottom.collapsed {
  transform: translateY(100%);
  transition: transform 0.4s cubic-bezier(0.22, 0.61, 0.36, 1);
}

.app-list-header {
  padding: 0.75rem;
  border-bottom: 1px solid rgba(0, 0, 0, 0.06);
  background: #fafafa;
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
  flex-shrink: 0;
}

@media (max-width: 480px) {
  .app-list-header {
    padding: 0.65rem;
  }
}

.header-top-row {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  width: 100%;
}

.search-box {
  flex: 1;
  min-width: 0;
}

.search-input {
  width: 100%;
  box-sizing: border-box;
  padding: 0 0.75rem;
  border: 1px solid #e0e0e0;
  border-radius: 4px;
  font-size: 0.85rem;
  outline: none;
  background: white;
  transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);
  box-shadow: 0 1px 2px rgba(0, 0, 0, 0.08);
  height: 28px;
  line-height: 28px;
}

.search-input:focus {
  border-color: #333;
  background: #fff;
  box-shadow: 0 0 0 2px rgba(0, 0, 0, 0.08);
}

.search-input::placeholder {
  color: rgba(0, 0, 0, 0.4);
}

.toggle-btn {
  background: white;
  border: 1px solid #e0e0e0;
  cursor: pointer;
  padding: 0;
  color: #333;
  border-radius: 4px;
  transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);
  flex-shrink: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 28px;
  height: 28px;
  box-shadow: 0 1px 2px rgba(0, 0, 0, 0.08);
}

.toggle-btn svg {
  width: 14px;
  height: 14px;
}

.toggle-btn:hover {
  background: #333;
  color: white;
  border-color: #333;
  transform: scale(1.05);
}

.toggle-btn:active {
  transform: scale(0.95);
}

/* 桌面端隐藏关闭按钮 */
.toggle-btn-desktop {
  display: none;
}

/* 移动端显示关闭按钮 */
@media (max-width: 768px) {
  .toggle-btn-desktop {
    display: flex;
  }
}

/* 设置面板 */
.settings-panel {
  flex: 1;
  display: flex;
  flex-direction: column;
  overflow: hidden;
  background: #fafafa;
}

.settings-header {
  padding: 0.85rem 1rem;
  border-bottom: 1px solid rgba(0, 0, 0, 0.06);
  display: flex;
  align-items: center;
  justify-content: space-between;
  flex-shrink: 0;
  background: #fafafa;
}

.settings-title {
  font-size: 0.85rem;
  color: #777;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: -0.01em;
  opacity: 0.9;
  flex: 1;
}

.settings-close-btn {
  background: white;
  border: 1px solid #e0e0e0;
  color: #666;
  cursor: pointer;
  padding: 0;
  line-height: 1;
  border-radius: 4px;
  transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);
  display: flex;
  align-items: center;
  justify-content: center;
  width: 28px;
  height: 28px;
  box-shadow: 0 1px 2px rgba(0, 0, 0, 0.08);
  flex-shrink: 0;
}

.settings-close-btn svg {
  width: 12px;
  height: 12px;
}

.settings-close-btn:hover {
  background: #333;
  color: white;
  border-color: #333;
  transform: scale(1.05);
}

.settings-close-btn:active {
  transform: scale(0.95);
}

.settings-content {
  flex: 1;
  overflow-y: auto;
  padding: 1.25rem 1rem;
  /* 自定义滚动条 */
  scrollbar-width: thin;
  scrollbar-color: rgba(0, 0, 0, 0.2) transparent;
}

.settings-content::-webkit-scrollbar {
  width: 6px;
}

.settings-content::-webkit-scrollbar-track {
  background: transparent;
}

.settings-content::-webkit-scrollbar-thumb {
  background: rgba(0, 0, 0, 0.2);
  border-radius: 3px;
}

.settings-content::-webkit-scrollbar-thumb:hover {
  background: rgba(0, 0, 0, 0.3);
}

.settings-section {
  margin-bottom: 2rem;
}

.settings-section:last-child {
  margin-bottom: 0;
}

.settings-label {
  font-size: 0.85rem;
  font-weight: 600;
  color: #555;
  margin-bottom: 0.85rem;
  letter-spacing: -0.01em;
  text-transform: uppercase;
  opacity: 0.9;
}

@media (max-width: 480px) {
  .settings-label {
    font-size: 0.8rem;
  }
}

.settings-options {
  display: flex;
  flex-direction: column;
  gap: 0.65rem;
}

.settings-option-btn {
  padding: 0.85rem 1.1rem;
  border: 1.5px solid rgba(0, 0, 0, 0.08);
  border-radius: 10px;
  background: white;
  color: #333;
  cursor: pointer;
  font-size: 0.9rem;
  font-weight: 500;
  transition: all 0.25s cubic-bezier(0.4, 0, 0.2, 1);
  text-align: left;
  box-shadow: 0 2px 4px rgba(0, 0, 0, 0.02);
}

.settings-option-btn:hover:not(.active) {
  background: #f8f9fa;
  border-color: rgba(0, 0, 0, 0.2);
  transform: translateY(-1px);
  box-shadow: 0 4px 8px rgba(0, 0, 0, 0.04);
}

.settings-option-btn:active {
  transform: translateY(0);
}

.settings-option-btn.active {
  background: #333;
  color: white;
  border-color: #333;
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
}

@media (max-width: 480px) {
  .settings-option-btn {
    padding: 0.75rem 0.95rem;
    font-size: 0.85rem;
  }
}

.settings-clear-btn {
  padding: 0.85rem 1.1rem;
  border: 1.5px solid rgba(220, 53, 69, 0.2);
  border-radius: 10px;
  background: white;
  color: #dc3545;
  cursor: pointer;
  font-size: 0.9rem;
  font-weight: 500;
  transition: all 0.25s cubic-bezier(0.4, 0, 0.2, 1);
  text-align: left;
  box-shadow: 0 2px 4px rgba(0, 0, 0, 0.02);
}

.settings-clear-btn:hover {
  background: #fff5f5;
  border-color: #dc3545;
  color: #c82333;
  transform: translateY(-1px);
  box-shadow: 0 4px 8px rgba(220, 53, 69, 0.1);
}

.settings-clear-btn:active {
  transform: translateY(0);
}

@media (max-width: 480px) {
  .settings-clear-btn {
    padding: 0.75rem 0.95rem;
    font-size: 0.85rem;
  }
}

/* 快捷键配置 */
.shortcut-config {
  display: flex;
  gap: 0.65rem;
  align-items: center;
}

.shortcut-input {
  flex: 1;
  padding: 0.85rem 1.1rem;
  border: 1.5px solid rgba(0, 0, 0, 0.08);
  border-radius: 10px;
  background: white;
  color: #333;
  font-size: 0.9rem;
  font-weight: 500;
  transition: all 0.25s cubic-bezier(0.4, 0, 0.2, 1);
  text-align: left;
  box-shadow: 0 2px 4px rgba(0, 0, 0, 0.02);
  cursor: pointer;
}

.shortcut-input:focus {
  outline: none;
  border-color: #667eea;
  box-shadow: 0 0 0 3px rgba(102, 126, 234, 0.1);
}

.shortcut-input:read-only {
  cursor: pointer;
}

.shortcut-btn {
  padding: 0.85rem 1.1rem;
  border: 1.5px solid rgba(0, 0, 0, 0.08);
  border-radius: 10px;
  background: white;
  color: #333;
  cursor: pointer;
  font-size: 0.9rem;
  font-weight: 500;
  transition: all 0.25s cubic-bezier(0.4, 0, 0.2, 1);
  box-shadow: 0 2px 4px rgba(0, 0, 0, 0.02);
  white-space: nowrap;
}

.shortcut-btn:hover {
  background: #f8f9fa;
  border-color: rgba(0, 0, 0, 0.2);
  transform: translateY(-1px);
  box-shadow: 0 4px 8px rgba(0, 0, 0, 0.04);
}

.shortcut-btn:active {
  transform: translateY(0);
}

.shortcut-hint {
  font-size: 0.75rem;
  color: #999;
  margin-top: 0.5rem;
  line-height: 1.4;
}

@media (max-width: 480px) {
  .shortcut-input,
  .shortcut-btn {
    padding: 0.75rem 0.95rem;
    font-size: 0.85rem;
  }
  
  .shortcut-hint {
    font-size: 0.7rem;
  }
}

.settings-checkbox-label {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  padding: 0.85rem 1.1rem;
  border: 1.5px solid rgba(0, 0, 0, 0.08);
  border-radius: 10px;
  background: white;
  cursor: pointer;
  font-size: 0.9rem;
  font-weight: 500;
  transition: all 0.25s cubic-bezier(0.4, 0, 0.2, 1);
  user-select: none;
  box-shadow: 0 2px 4px rgba(0, 0, 0, 0.02);
}

.settings-checkbox-label:hover:not(.disabled) {
  background: #f8f9fa;
  border-color: rgba(0, 0, 0, 0.2);
  transform: translateY(-1px);
  box-shadow: 0 4px 8px rgba(0, 0, 0, 0.04);
}

.settings-checkbox-label:active:not(.disabled) {
  transform: translateY(0);
}

.settings-checkbox-label.disabled {
  opacity: 0.5;
  cursor: not-allowed;
}

@media (max-width: 480px) {
  .settings-checkbox-label {
    padding: 0.75rem 0.95rem;
    font-size: 0.85rem;
  }
}

.settings-checkbox {
  width: 20px;
  height: 20px;
  cursor: pointer;
  accent-color: #333;
}

.settings-checkbox-label.disabled .settings-checkbox {
  cursor: not-allowed;
}

/* 历史应用区域 */
.history-section {
  padding: 0.85rem 1rem;
  border-bottom: 1px solid rgba(0, 0, 0, 0.06);
  flex-shrink: 0;
  background: #fafafa;
}

.history-title-wrapper {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-bottom: 0.65rem;
}

/* 折叠状态下移除底部间距 */
.history-title-wrapper.collapsed {
  margin-bottom: 0;
}

.history-title {
  font-size: 0.85rem;
  color: #777;
  font-weight: 600;
  flex: 1;
  display: flex;
  align-items: center;
  gap: 0.5rem;
  cursor: pointer;
  user-select: none;
  text-transform: uppercase;
  letter-spacing: -0.01em;
  opacity: 0.9;
}

/* 确保移动端"最近应用"字体大小与"我的应用"一致 */
.history-title-text-mobile {
  font-size: 0.85rem;
  color: #777;
  font-weight: 600;
}

.history-collapse-icon {
  font-size: 0.7rem;
  transition: transform 0.25s cubic-bezier(0.4, 0, 0.2, 1);
  display: inline-block;
  opacity: 0.6;
}

.history-collapse-icon.collapsed {
  transform: rotate(-90deg);
}

.clear-history-btn {
  background: white;
  border: 1px solid #e0e0e0;
  color: #666;
  cursor: pointer;
  padding: 0;
  line-height: 1;
  border-radius: 4px;
  transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);
  display: flex;
  align-items: center;
  justify-content: center;
  width: 28px;
  height: 28px;
  box-shadow: 0 1px 2px rgba(0, 0, 0, 0.08);
  flex-shrink: 0;
}

.clear-history-btn svg {
  width: 12px;
  height: 12px;
}

.clear-history-btn:hover {
  background: #333;
  color: white;
  border-color: #333;
  transform: scale(1.05);
}

.clear-history-btn:active {
  transform: scale(0.95);
}

.history-apps {
  display: flex;
  gap: 0.6rem;
  flex-wrap: wrap;
}

/* 桌面端和移动端标题文字切换 */
.history-title-text-mobile {
  display: none;
}

/* 移动端：历史应用一行显示两个，最多3行 */
@media (max-width: 768px) {
  .floating-app-list.position-left .history-title-text-desktop {
    display: none;
  }
  
  .floating-app-list.position-left .history-title-text-mobile {
    display: inline;
    font-size: 0.85rem;
    color: #999;
    font-weight: 500;
  }
  
  .floating-app-list.position-left .history-apps {
    display: grid;
    grid-template-columns: repeat(2, 1fr);
    gap: 0.5rem;
    /* 限制最多显示3行：每行高度约48px，加上2个gap（0.5rem * 2），总共约160px */
    max-height: calc(48px * 3 + 0.5rem * 2);
    overflow-y: auto;
    overflow-x: hidden;
    /* 隐藏滚动条 */
    scrollbar-width: none;
    -ms-overflow-style: none;
  }
  
  .floating-app-list.position-left .history-apps::-webkit-scrollbar {
    display: none;
  }
  
  /* 移动端：搜索框和标题区域优化 */
  .floating-app-list.position-left .app-list-header {
    padding: 0.5rem;
  }
  
  .floating-app-list.position-left .history-section {
    padding: 0;
  }
  
  /* 确保history-apps的布局与app-list-content一致 - 添加相同的padding */
  .floating-app-list.position-left .history-apps {
    margin-top: 0;
    padding: 0.5rem;
  }
  
  .floating-app-list.position-left .history-title-wrapper {
    padding: 0.5rem;
    margin-bottom: 0;
    border-bottom: 1px solid #e0e0e0;
    flex-shrink: 0;
    display: flex;
    align-items: center;
    justify-content: space-between;
  }
  
  .floating-app-list.position-left .history-title-wrapper.collapsed {
    margin-bottom: 0;
    border-bottom: none;
  }
}

.history-app-item {
  width: 44px;
  height: 44px;
  border-radius: 12px;
  cursor: pointer;
  transition: all 0.25s cubic-bezier(0.4, 0, 0.2, 1);
  display: flex;
  align-items: center;
  justify-content: center;
  position: relative;
  overflow: hidden;
  background: rgba(255, 255, 255, 0.8);
  box-shadow: 0 2px 6px rgba(0, 0, 0, 0.04);
}

.history-app-item:hover {
  background: rgba(255, 255, 255, 1);
  transform: translateY(-2px) scale(1.05);
  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08);
}

.history-app-item:active {
  transform: translateY(0) scale(1);
}

.history-app-item.active {
  background: rgba(0, 0, 0, 0.08);
  box-shadow: 0 0 0 2px rgba(0, 0, 0, 0.2);
}

.history-app-icon {
  width: 100%;
  height: 100%;
  border-radius: 12px;
  object-fit: cover;
  display: block;
}

.history-app-icon-placeholder {
  width: 100%;
  height: 100%;
  border-radius: 12px;
  display: flex;
  align-items: center;
  justify-content: center;
  background: #667eea;
  color: white;
  font-weight: 600;
  font-size: 1.1rem;
  text-transform: uppercase;
}

/* 应用列表包装器 */
.app-list-wrapper {
  flex: 1;
  display: flex;
  flex-direction: column;
  overflow: hidden;
}

/* 应用列表标题区域 */
.app-list-title-section {
  padding: 0.85rem 1rem;
  border-bottom: 1px solid rgba(0, 0, 0, 0.06);
  flex-shrink: 0;
  background: #fafafa;
}

.app-list-title-text-desktop {
  display: none;
}

.app-list-title-text-mobile {
  display: none;
  font-size: 0.85rem;
  color: #777;
  font-weight: 600;
  align-items: center;
  justify-content: space-between;
  gap: 0.6rem;
  text-transform: uppercase;
  letter-spacing: -0.01em;
}

.app-list-title-main {
  flex: 1;
  opacity: 0.9;
}

.app-list-stats {
  display: flex;
  align-items: center;
  gap: 0.85rem;
  padding: 0.3rem 0.6rem;
  background: rgba(255, 255, 255, 0.7);
  border-radius: 8px;
}

.app-stat-item {
  display: flex;
  align-items: center;
  gap: 0.35rem;
  font-size: 0.75rem;
  color: #666;
}

.app-stat-icon {
  font-size: 0.9rem;
  line-height: 1;
  opacity: 0.8;
}

.app-stat-count {
  font-weight: 700;
  color: #444;
  font-size: 0.8rem;
}

/* 应用列表内容 */
.app-list-content {
  flex: 1;
  overflow-y: auto;
  padding: 0.75rem;
  /* 自定义滚动条样式 */
  scrollbar-width: thin;
  scrollbar-color: rgba(0, 0, 0, 0.2) transparent;
}

.app-list-content::-webkit-scrollbar {
  width: 6px;
}

.app-list-content::-webkit-scrollbar-track {
  background: transparent;
}

.app-list-content::-webkit-scrollbar-thumb {
  background: rgba(0, 0, 0, 0.2);
  border-radius: 3px;
}

.app-list-content::-webkit-scrollbar-thumb:hover {
  background: rgba(0, 0, 0, 0.3);
}

/* 移动端：应用列表一行显示两个，隐藏文字，显示"我的应用"标题 */
@media (max-width: 768px) {
  /* 隐藏关闭按钮 */
  .floating-app-list.position-left .toggle-btn-desktop {
    display: none;
  }
  
  /* 显示"我的应用"标题 */
  .floating-app-list.position-left .app-list-title-text-mobile {
    display: flex;
  }
  
  .floating-app-list.position-left .app-list-title-section {
    padding: 0.5rem;
    flex-shrink: 0;
  }
  
  .floating-app-list.position-left .app-list-stats {
    gap: 0.5rem;
  }
  
  .floating-app-list.position-left .app-stat-item {
    font-size: 0.7rem;
    gap: 0.2rem;
  }
  
  .floating-app-list.position-left .app-stat-icon {
    font-size: 0.85rem;
  }
  
  .floating-app-list.position-left .app-list-content {
    display: grid;
    grid-template-columns: repeat(2, 1fr);
    gap: 0.5rem;
    padding: 0.5rem;
  }
  
  .floating-app-list.position-left .app-list-item {
    flex-direction: column;
    align-items: center;
    padding: 0.5rem;
    margin-bottom: 0;
    text-align: center;
  }
  
  .floating-app-list.position-left .app-list-icon-wrapper {
    margin-right: 0;
    margin-bottom: 0;
    width: 48px;
    height: 48px;
  }
  
  .floating-app-list.position-left .app-list-icon,
  .floating-app-list.position-left .app-list-icon-placeholder {
    border-radius: 12px;
  }
  
  .floating-app-list.position-left .app-list-title {
    display: none;
  }
  
  /* 将我的应用列表样式套用到最近应用 - 完全一致 */
  .floating-app-list.position-left .history-app-item {
    flex-direction: column;
    align-items: center;
    padding: 0.5rem;
    margin-bottom: 0;
    text-align: center;
    /* 确保与app-list-item完全一致 */
    width: auto;
    height: auto;
    border-radius: 8px;
    cursor: pointer;
    transition: all 0.2s;
    display: flex;
    position: relative;
    overflow: visible;
  }
  
  /* 移动端hover状态 - 移除transform以保持一致 */
  .floating-app-list.position-left .history-app-item:hover {
    transform: none;
  }
  
  /* 最近应用图标样式 - 与我的应用图标包装器大小一致（48px x 48px） */
  .floating-app-list.position-left .history-app-icon,
  .floating-app-list.position-left .history-app-icon-placeholder {
    width: 48px;
    height: 48px;
    border-radius: 12px;
  }
}

.app-list-content::-webkit-scrollbar {
  width: 6px;
}

.app-list-content::-webkit-scrollbar-track {
  background: transparent;
}

.app-list-content::-webkit-scrollbar-thumb {
  background: #c0c0c0;
  border-radius: 3px;
}

.app-list-content::-webkit-scrollbar-thumb:hover {
  background: #a0a0a0;
}

/* 只在内容溢出时显示滚动条 */
.app-list-content:not(:hover)::-webkit-scrollbar-thumb {
  background: transparent;
}

.app-list-item {
  display: flex;
  align-items: center;
  padding: 0.85rem;
  border-radius: 12px;
  cursor: pointer;
  transition: all 0.25s cubic-bezier(0.4, 0, 0.2, 1);
  margin-bottom: 0.35rem;
  background: rgba(255, 255, 255, 0.6);
  border: 1px solid transparent;
}

.app-list-item:hover {
  background: rgba(255, 255, 255, 1);
  transform: translateX(4px);
  border-color: rgba(102, 126, 234, 0.15);
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.04);
}

.app-list-item:active {
  transform: translateX(2px);
}

.app-list-item.active {
  background: rgba(0, 0, 0, 0.08);
  color: #333;
  border-color: rgba(0, 0, 0, 0.2);
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.12);
}

.app-list-icon-wrapper {
  position: relative;
  width: 42px;
  height: 42px;
  margin-right: 0.85rem;
  flex-shrink: 0;
}

@media (max-width: 480px) {
  .app-list-icon-wrapper {
    width: 48px;
    height: 48px;
  }
}

.app-list-icon {
  width: 100%;
  height: 100%;
  border-radius: 10px;
  object-fit: cover;
  display: block;
  box-shadow: 0 2px 4px rgba(0, 0, 0, 0.06);
}

.running-badge {
  position: absolute;
  top: -3px;
  right: -3px;
  width: 12px;
  height: 12px;
  background: #52c41a;
  border: 2.5px solid white;
  border-radius: 50%;
  box-shadow: 0 2px 4px rgba(0, 0, 0, 0.15);
}


.app-list-icon-placeholder {
  width: 100%;
  height: 100%;
  border-radius: 10px;
  display: flex;
  align-items: center;
  justify-content: center;
  background: #667eea;
  color: white;
  font-weight: 700;
  font-size: 1rem;
  text-transform: uppercase;
  box-shadow: 0 2px 4px rgba(0, 0, 0, 0.06);
}

.app-list-title {
  font-size: 0.95rem;
  font-weight: 500;
  color: #333;
  overflow: hidden;
  letter-spacing: -0.01em;
  text-overflow: ellipsis;
  white-space: nowrap;
  flex: 1;
}

.app-list-item.active .app-list-title {
  color: #333;
  font-weight: 600;
}

/* 展开按钮容器 */
/* 浮动按钮：简洁圆形设计 */
.expand-btn {
  position: fixed;
  z-index: 2000;
  width: 56px;
  height: 56px;
  display: flex;
  align-items: center;
  justify-content: center;
  background: white;
  border: 1px solid rgba(0, 0, 0, 0.08);
  border-radius: 50%;
  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08), 0 2px 4px rgba(0, 0, 0, 0.04);
  cursor: pointer;
  user-select: none;
  touch-action: none;
  /* 只过渡 transform、box-shadow、background、border，不过渡 left/top，让拖动更跟手 */
  transition: transform 0.25s cubic-bezier(0.4, 0, 0.2, 1),
              box-shadow 0.25s ease,
              background 0.25s ease,
              border-color 0.25s ease;
}

.expand-btn:hover {
  background: #333;
  border-color: #333;
  box-shadow: 0 6px 20px rgba(0, 0, 0, 0.15), 0 2px 6px rgba(0, 0, 0, 0.08);
  transform: scale(1.05);
}

.expand-btn:hover .expand-btn-icon {
  color: white;
}

.expand-btn:active {
  transform: scale(0.95);
}

.expand-btn.is-dragging {
  cursor: grabbing;
  box-shadow: 0 8px 24px rgba(0, 0, 0, 0.2), 0 4px 8px rgba(0, 0, 0, 0.1);
  transform: scale(1.08);
  transition: transform 0.25s cubic-bezier(0.4, 0, 0.2, 1), box-shadow 0.25s ease !important;
  /* 拖动时禁用 left/top 的 transition，让位置更新立即生效 */
}

.expand-btn-icon {
  color: #333;
  transition: color 0.25s ease;
  pointer-events: none;
}

/* 响应式设计 - 其他位置的侧边栏在移动端全宽 */
@media (max-width: 768px) {
  .floating-app-list.position-top,
  .floating-app-list.position-bottom {
    width: 100%;
  }
}

/* 快捷切换面板 */
.quick-switch-panel {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  z-index: 10000;
  display: flex;
  align-items: flex-start;
  justify-content: center;
  padding-top: 15vh;
  background: rgba(0, 0, 0, 0.3);
  backdrop-filter: blur(4px);
  animation: fadeIn 0.2s ease;
}

@keyframes fadeIn {
  from {
    opacity: 0;
  }
  to {
    opacity: 1;
  }
}

.quick-switch-content {
  width: 90%;
  max-width: 500px;
  background: white;
  border-radius: 12px;
  box-shadow: 0 20px 60px rgba(0, 0, 0, 0.3);
  overflow: hidden;
  animation: slideDown 0.2s ease;
}

@keyframes slideDown {
  from {
    opacity: 0;
    transform: translateY(-20px);
  }
  to {
    opacity: 1;
    transform: translateY(0);
  }
}

.quick-switch-input {
  width: 100%;
  padding: 16px 20px;
  border: none;
  border-bottom: 1px solid #e5e5e5;
  font-size: 16px;
  outline: none;
  background: transparent;
  color: #333;
}

.quick-switch-input::placeholder {
  color: #999;
}

.quick-switch-apps {
  max-height: 400px;
  overflow-y: auto;
  padding: 8px 0;
  /* 自定义滚动条样式，与侧边栏保持一致 */
  scrollbar-width: thin;
  scrollbar-color: #c0c0c0 transparent;
}

.quick-switch-apps::-webkit-scrollbar {
  width: 6px;
}

.quick-switch-apps::-webkit-scrollbar-track {
  background: transparent;
}

.quick-switch-apps::-webkit-scrollbar-thumb {
  background: #c0c0c0;
  border-radius: 3px;
}

.quick-switch-apps::-webkit-scrollbar-thumb:hover {
  background: #a0a0a0;
}

/* 只在内容溢出时显示滚动条 */
.quick-switch-apps:not(:hover)::-webkit-scrollbar-thumb {
  background: transparent;
}

.quick-switch-app-item {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 12px 20px;
  cursor: pointer;
  transition: background-color 0.15s ease;
}

.quick-switch-app-item:hover {
  background-color: #f5f5f5;
}

.quick-switch-app-item.selected {
  background-color: #667eea;
  color: white;
}

.quick-switch-app-item.selected .quick-switch-app-title {
  color: white;
}

.quick-switch-app-icon {
  width: 32px;
  height: 32px;
  border-radius: 6px;
  object-fit: cover;
  flex-shrink: 0;
}

.quick-switch-app-icon-placeholder {
  width: 32px;
  height: 32px;
  border-radius: 6px;
  background: #667eea;
  color: white;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 14px;
  font-weight: 600;
  flex-shrink: 0;
}

.quick-switch-app-item.selected .quick-switch-app-icon-placeholder {
  background: rgba(255, 255, 255, 0.3);
}

.quick-switch-app-title {
  flex: 1;
  font-size: 15px;
  color: #333;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.quick-switch-empty {
  padding: 40px 20px;
  text-align: center;
  color: #999;
  font-size: 14px;
}
</style>

<style>
/* 全局样式：拖动浮动按钮时禁用iframe的pointer-events */
body.dragging-float-btn iframe {
  pointer-events: none !important;
}
</style>
